Intel one API (icx/icpx)時代のmakefile
Intel one APIコンパイラでのc++コンパイル(Linux)
Intel one APIが無料で使える時代になっていますが、oneAPIになってからC++のコンパイラがicc/icpcから、icx/icpxに移行しています。2023年現在ではまだicpcも使えますが、コンパイル時に「レガシーなので移行してね」的なメッセージが出てきて、2023年3Qからサポート外になります。
そんなわけで、「数値シミュレーション系で、コンパイルについてはあまり気にしていない。先人のmakefileを受け継いでいるだけ」という人は、makefileやCMakeListを書き換える必要があるのですが、ネットではあまり情報がなく、私も試行錯誤で成功したので、メモとして残しておきます。
makefileのサンプル
icx/icpx用のmakefileは、基本的にはicc/ipcpのオプションがそのまま使えます。が、どうもちょっとだけ変えないと動かないようです。注意するのはファイル間最適化をするためのipoオプション。icpcではCFLAGSのところに書けばOKだったと思いますが、icpxの場合、OPTSのところに書いたほうが無難なようです(CFLAGでも動くのですが、静的ライブラリとリンクするとエラーになる…?)
以下にサンプルを示します。makefileのあるフォルダのcppを対象にしてコンパイルします。中間ファイルは./objファイルに作ります。ライブラリをリンクする場合はLIBSに適宜追加してください。
CXX = icpx
CFLAGS = -O3 -std=c++14 -xhost -openmp
OPTS = -qmkl -ipo
LIBS =
OBJDIR = ./obj
SOURCES = $(wildcard *.cpp)
OBJECTS = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.o))
#target file
TARGET = test_prog
$(TARGET): $(OBJECTS)
$(CXX) -o $@ $^ $(LDFLAGS) $(LIBS) $(OPTS)
$(OBJDIR)/%.o: %.cpp
@if [ ! -d $(OBJDIR) ]; \
then echo "mkdir -p $(OBJDIR) dirs"; mkdir -p $(OBJDIR); \
fi
@[ -d $(OBJDIR) ]
$(CXX) -c $(CFLAGS) $(INDS) -o $@ $<
clean:
rm $(OBJDIR)/*.o
rm $(TARGET)
depend:
makedepend -- -Y -- $(SOURCES)
これで基本的なプログラムはコンパイルできるはず。
静的ライブラリ(.aファイル)のmakefile
静的ライブラリ(.aファイル)を作る場合も、基本的にはicpc時代と同じで行けます。…が、これが一番はまりました。
cppファイルをコンパイルして.oファイルを作り、最終的には、g++ならarコマンド、icpcならxiarコマンドで.aファイルを作成すると思います。icpxの場合はどうするんだ!ということで調べてもほとんど出てこないのですが、icpxはclang系列のコンパイラのようなので、「llvm-ar」コマンドで.aファイルを作るようです。そこまではいいのですが、clangデフォルトのllvm-arではintelじゃないのでダメです。というわけでintelコンパイラのファイルをひたすら探してみると・・・あります。インテルのllvm-ar。こいつを使えばOKです。インストールフォルダを変えていない限り、このコマンドは「/opt/intel/oneapi/compiler/latest/bin/compiler/」にあります。
というわけで、icpx用の静的ライブラリを作るmakefileは以下のようになります。
※ARXのところは、単にllvm-arとして、
PATH=/opt/intel/oneapi/compiler/latest/bin/compiler/:$PATH
のように、intelのllvm-arのPATHを通しておいてもOKです。こっちの方が個人的には好みですが。
CXX = icpx
ARX = /opt/intel/oneapi/compiler/latest/bin/compiler/llvm-ar
CFLAGS = -O3 -std=c++14 -xhost -openmp
OPTS = -qmkl -ipo
LIBS =
OBJDIR = ./obj
SOURCES = $(wildcard *.cpp)
OBJECTS = $(addprefix $(OBJDIR)/, $(SOURCES:.cpp=.o))
#target file
TARGET = ./libTest.a
$(TARGET): $(OBJECTS)
$(ARX) rcs $@ $^
$(OBJDIR)/%.o: %.cpp
@if [ ! -d $(OBJDIR) ]; \
then echo "mkdir -p $(OBJDIR)"; mkdir -p $(OBJDIR); \
fi
@[ -d $(OBJDIR) ]
$(CXX) -c $(CFLAGS) $(INDS) -o $@ $<
clean:
rm -r $(OBJDIR)
rm $(TARGET)
depend:
makedepend -- -Y -- $(SOURCES)
CMakeListの書き方
CMakeを使っている場合はCMakeList.txtを書き換えてあげましょう。VERSION 3.2以上ならicpxも認識してくれるようです。
私はチーム開発しないためCMakeListは詳しくない&そこまで興味がないので、超適当な記入例ですが、例えば以下のようにすれば動きました。最初のsetでコンパイラを指定し、あとは自動で分岐するような例です。
# CMakeのバージョンを設定
cmake_minimum_required(VERSION 3.21)
#コンパイラ変更
#set(CMAKE_CXX_COMPILER icpc)
set(CMAKE_CXX_COMPILER icpx)
#
if(CMAKE_CXX_COMPILER MATCHES "icpc")
message("Intel classical Compiler use !")
elseif(CMAKE_CXX_COMPILER MATCHES "icpx")
message("Intel new Compiler use !")
set(CMAKE_AR "/opt/intel/oneapi/compiler/latest/linux/bin-llvm/llvm-ar")
endif()
#
project(Test CXX)
#コンパイル設定
add_executable(test.out main.cpp)
#オプションとライブラリリンクの設定
if(CMAKE_CXX_COMPILER MATCHES "icpc")
message("Intel Classical Compiler use in Example !")
target_compile_options(test.out PUBLIC -std=c++14 -O3 -xHost -openmp -ipo)
target_link_libraries(test.out PUBLIC -qmkl)
#
elseif(CMAKE_CXX_COMPILER MATCHES "icpx")
message("Intel New Compiler use in Example !")
target_compile_options(test.out PUBLIC -std=c++14 -O3 -xHost -openmp)
target_link_libraries(test.out PUBLIC -qmkl -ipo)
#
else()
target_compile_options(test.out PUBLIC -std=c++14 -O3 -fopenmp)
target_link_libraries(test.out PUBLIC -lgomp)
endif()
まとめ
icpx時代のmakefileについて調べました。基本的なオプションはそのまま流用できますが、細かいところが変わっているので注意してください!
(今のところ、ipoの位置と、静的ライブラリのllvm-ar、くらいです)
Discussion