💭

Intel one API (icx/icpx)時代のmakefile

2023/06/30に公開

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に適宜追加してください。

MakeFile
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です。こっちの方が個人的には好みですが。

MakeFile
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でコンパイラを指定し、あとは自動で分岐するような例です。

CMakeLists.tx
 # 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