C++/JavaとWin/Linuxの組み合わせにおけるビルドについて整理する

# はじめに
本記事では、C++とJavaという２つのプログラミング言語について、ビルド周りの知識を整理します。
具体的には、各言語における「基本的なビルド方法」、「共有ライブラリの利用方法」、「ビルドツール」について整理します。
その際、WindowsとLinuxとで相違がある場合には、その点についても触れます。

本記事の投稿目的は、投稿者自身が知識を整理することであり、内容に間違いが含まれる可能性があります。
間違いを見つけた方はコメントなどで指摘をお願いします。

# 基本的なビルド方法
本節では、コマンドラインからビルドを行う基本的な方法について整理します。
「ビルド = コンパイル + リンク」として説明します。

### C++
main.cpp, hoge.cpp, hoge.hという3つのファイルからプロジェクトが構成されるとします。
コンパイルは、

```
g++ -c main.cpp hoge.cpp
```
リンクは、

```
g++ main.o hoge.o
```
というコマンドで行うことができ、実行ファイル(Linuxではa.out, Windowsではa.exe)が生成されます。
-cは「コンパイルのみを行う」オプションであり、このオプションを省くと一気に実行ファイルの生成まで済ませることができます。

```
g++ main.cpp hoge.cpp
```
### Java
Main.java, Hoge.javaという2つのファイルからプロジェクトが構成されるとします。
コンパイルは、

```
javac Main.java
```
というコマンドで行うことができ、Main.classとHoge.classというファイルが生成されます。
依存関係は自動解決してくれるので、Hoge.javaを引数に加える必要はありません。
また、リンクは実行時に行うため、コマンドで明示的にリンクを行う必要はありません。
実行は、

```
java Main
```
というコマンドで行います。

# 共有ライブラリの利用方法
共有ライブラリの利用方法についてOpenCVを例に説明します。
OpenCVを例とした理由は投稿者にとって身近なライブラリだというだけなので、OpenCVをよく知らない方は別のライブラリに置き換えて読んでいただければと思います。

### C++(Linux)
インクルードパス、ライブラリパス、共有ライブラリファイルの３つをg++のオプションで指定します。
例えば、インクルードパス：/usr/local/include/opencv4, ライブラリパス：/usr/local/lib, 共有ライブラリファイル：libopencv_core.soの場合は、以下のようにします。

```
g++ main.cpp -I/usr/local/include/opencv4 -L/usr/local/lib -lopencv_core
```

### C++(Windows)
Windowsの場合、-lオプションでインポートライブラリ(.libファイル)を指定します。
インポートライブラリファイル名がopencv_world420.libの場合、以下のコマンドでビルドします。

```
g++ main.cpp -IC:/opencv/build/include -LC:/opencv/build/x64/lib -lopencv_world420
```

実行時は.libファイルと対となる.dllファイル(共有ライブラリ本体)にパスを通す必要があります。
.libファイルと.dllファイルの関係については、以下のサイトが参考になるかと思います。
http://exlight.net/devel/windows/dll/windll.html

### Java(Linux)
Javaでは、jarファイルが上記のインポートライブラリのような役割を担っているため、以下のように、classpathにjarファイルを指定してビルドを行います。

```
javac -cp /usr/local/share/java/opencv4/opencv-430.jar Main.java
```

そして、実行時には共有ライブラリ本体である.soファイルへのパスをjava.library.pathとして与える必要があります。
(説明は省略しますが、ソースコード上でもSystem.loadLibrary関数で.soファイルをロードする必要があります)
また、実行時にもclasspathが必要で、かつ、実行したいclassファイルのパス(.)も指定する必要があります。

```
java -cp .:/usr/local/share/java/opencv4/opencv-430.jar -Djava.library.path=/usr/local/share/java/opencv4 Main
```
詳細は以下のページが参考になるかと思います。
https://stackoverflow.com/questions/28727766/how-to-add-an-external-library-opencv-jar-file-to-the-java-build-path-from-th

### Java(Windows)
Windowsの場合、.soファイルの代わりに.dllファイルをロードし、classpathの区切り文字が":"ではなく";"となります。

```
javac -cp C:/opencv/build/java/opencv-430.jar Main.java
java -cp .;C:/opencv/build/java/opencv-420.jar -Djava.library.path=C:/opencv/build/java/x64 Main
```

# ビルドツール
本節では、C言語のビルドツールであるCMakeとJavaのビルドツールであるGradleを紹介します。

### CMake
CMakeの説明をする前に、makeについて触れておきます。
makeはビルドツールの草分け的存在であり、Makefileにビルドルールを書いておくことで、ビルドを自動化できます。

CMakeはC言語のソースコードをインストールする際に、CMake→make→make installという手順でよく利用されます。
この各手順では、以下のような作業がなされています。

* CMake : CMakeLists.txtに書かれたルールにしたがって、Makefileを作成する
* make : Makefileに書かれたルールに従ってビルドする
* make install : Makefileに書かれたルールに従って、ビルド済ファイルのコピーなどを行う

OpenCVを使う例だと、CMakeLists.txtは以下のような内容になります。
(pkg_configを利用しない場合)

```
cmake_minimum_required(VERSION 3.10)
project(Main)

add_executable(Main main.cpp)

target_include_directories(Main
    PRIVATE
    /usr/local/include/opencv4
)

target_link_libraries(Main
    PRIVATE
    /usr/local/lib/libopencv_core.so
)
```

### Gradle
Gradleについては自分用のメモとして、build.gradleの中身のみ載せておきます。

```
apply plugin: 'java'

dependencies {
    compile files("/usr/local/share/java/opencv4/opencv-430.jar")
}
```

# おわりに
本記事では、C++とJavaという２つのプログラミング言語について、ビルド周りの知識を整理しました。
元々はIDEで隠蔽されているビルド処理などについても触れるつもりだったのですが、必要性がいまいち分からなくなってきたので、この辺りで終わりたいと思います。
結果的に20年前の記事みたいな内容になってしまいましたが、参考にしていただければ幸いです。