LoginSignup
11
7

More than 3 years have passed since last update.

M1 MacでのコマンドラインからのUniversal Binary作成

Last updated at Posted at 2021-02-14

Universal Binary

macOSはARMやx86_64や32bit i386やpowerpc用のバイナリを一つのバイナリにまとめて複数のアーキテクチャに対応できるUniversal Binaryに対応しています。標準の開発ツールのXCodeのGUIでもUniversal Binaryのビルドが可能ですが、既存のオープンソースのコードを利用する場合などコマンドラインでUniversal Binaryをビルドする方が便利な場面もあります。M1 Macのコマンドラインでの手順をまとめました。

作業環境

~/Downloads/で作業します。

$ cd ~/Downloads/

未インストールの場合はCommand line tools for Xcodeをインストールしてください。

$ xcode-select --install

lipo

lipoコマンドで複数のバイナリを1つのバイナリにまとめることができます。ARMバイナリとx86_64バイナリをそれぞれ独立してビルドし、lipoコマンドでARMバイナリとx86_64バイナリを一つにまとめることでARMとx86_64両対応のUniversal Binaryが作成できます。

次の内容でtest.cを作成します。現在の実行環境を表示するarchコマンドを実行するプログラムです。

#include <stdlib.h>

int main()
{
  system("arch");
  return 0;
}

-archオプションを使用してARMバイナリのtest.armとx86_64バイナリのtest.x86_64をビルドします。fileコマンドでどちらのバイナリか確認して実行します。

$ clang -o test.arm -arch arm64 test.c
$ clang -o test.x86_64 -arch x86_64 test.c
$ file test.*
test.arm:    Mach-O 64-bit executable arm64
test.c:      c program text, ASCII text
test.x86_64: Mach-O 64-bit executable x86_64
$ ./test.arm 
arm64
$ ./test.x86_64 
i386

lipoコマンドで1つのバイナリであるtestにまとめます。

$ lipo -create test.arm test.x86_64 -output test

fileコマンドで確認しそのままarmで実行とarch -x86_64でx86_64として実行の両方を試します。

$ file test
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64): Mach-O 64-bit executable x86_64
test (for architecture arm64):  Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -x86_64 ./test
i386

clangで直接生成

次に、clangのオプションを利用して直接Universal Binaryを作成します。上記のtest.cをそのまま使います。

普通にビルドした場合

ARMバイナリが生成されるのでARMとしては実行できますがx86_64としては実行できません。

$ clang -o test test.c
$ file test                        
test: Mach-O 64-bit executable arm64
$ ./test
arm64

$ arch -arm64 ./test  
arm64

$ arch -x86_64 ./test
arch: posix_spawnp: ./test: Bad CPU type in executable

同様にx86_64としてビルドした場合x86_64として実行できますがARMとしては実行できません。

$ clang -arch x86_64 -o test test.c  
$ file test
test: Mach-O 64-bit executable x86_64
$ ./test
i386
$ arch -x86_64 ./test              
i386

$ arch -arm64 ./test
arch: posix_spawnp: ./test: Bad CPU type in executable

Universal Binaryとしてビルドした場合

clangに-arch x86_64 -arch arm64をオプションを指定してUniversal Binaryとしてビルドします。armとしてもx86_64としても実行できるようになります。

$ clang -arch x86_64 -arch arm64 -o test test.c
$  file test
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64): Mach-O 64-bit executable x86_64
test (for architecture arm64):  Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -arm64 ./test
arm64
$ arch -x86_64 ./test
i386

Rosetta2環境でビルドした場合

Rosetta2環境でビルドすると標準ではx86_64バイナリが生成されます。archコマンドでx86_64環境のzshに移って確認します。

$ arch -x86_64 /bin/zsh
$ clang -o test test.c
$ file test
test: Mach-O 64-bit executable x86_64
$ ./test
i386

なおRosetta2環境下からARMバイナリを実行しARMバイナリがarchを呼ぶ場合はx86_64としてarchコマンドを実行するようです。

$ clang -arch arm64 -o test test.c
$ file test                       
test: Mach-O 64-bit executable arm64
$ ./test
i386

Rosetta2環境から抜けます。

$ exit

autotoolsの場合

autotoolsはconfigureスクリプトを使って様々な環境に適合できるよう調整したりビルドオプションを指定してビルドできるようにするための開発ツールです。configureスクリプトを使ってmakeコマンド用のMakefileを作成します。GNUをはじめ多くのオープンソースプログラムで使われています。

準備としてbrewからautoconf, automake, libtoolをインストールします。

$ brew install autoconf automake libtool

brewが未インストールの場合は先にbrewをインストールして上のコマンドを実行してください。

$ arch -arm64e /bin/bash -c "$(curl -fsSL $ https://raw.githubusercontent.com/Homebrew/install/master/install.sh)"

自作のautotools対応プログラムの通常ビルド

最小限のautotools対応プログラムを作ってUniversal Binaryとしてビルドします。特別な対応は不要でconfigureスクリプトにCFLAGSやLDFLAGSを指定するだけでUniversal Binaryとしてのビルドが可能です。

autotools-test以下にMakefile.am, src/test.c, src/Makefile.amを作成します。

$ mkdir autotools-test
$ cd autotools-test
$ mkdir src

Makefile.am

SUBDIRS=src

src/Makefile.am

bin_PROGRAMS=test
test_SOURCES=test.c

src/test.cは上記をコピーしてください。

$ cp ../test.c src/

autoscanを実行しconfigure.scanをconfigure.acに変更し、中の

AC_INIT([FULL-PACKAGE-NAME], [VERSION], [BUG-REPORT-ADDRESS])

AC_INIT([test], [1.0], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE

に書き換えます。

#                                               -*- Autoconf -*-
# Process this file with autoconf to produce a configure script.

AC_PREREQ([2.69])
AC_INIT([test], [1.0], [BUG-REPORT-ADDRESS])
AM_INIT_AUTOMAKE
AC_CONFIG_SRCDIR([src/test.c])
AC_CONFIG_HEADERS([config.h])

# Checks for programs.
AC_PROG_CC

# Checks for libraries.

# Checks for header files.
AC_CHECK_HEADERS([stdlib.h])

# Checks for typedefs, structures, and compiler characteristics.

# Checks for library functions.

AC_CONFIG_FILES([Makefile
                 src/Makefile])
AC_OUTPUT

あとは必要なコマンドを実行してconfigureスクリプトを作成します。

$ aclocal
$ autoheader
$ touch NEWS README AUTHORS ChangeLog
$ automake -a -c
$ autoconf

configureしてmakeすればARMバイナリが生成され問題なく実行でます。

./configure
make
$ file src/test
src/test: Mach-O 64-bit executable arm64
$ src/test
arm64

クリーンしておきます。

$ make clean

自作のautotools対応プログラムのUniversal Binaryビルド

CFLAGSとLDFLAGSにそれぞれ"-arch x86_64 -arch arm64"を指定することでARMとx86_64両対応でビルドされます。envコマンドで環境変数に値を与えるかexportで環境変数を設定してください。


$ env CFLAGS="-arch x86_64 -arch arm64" LDFLAGS="-arch x86_64 -arch arm64" ./configure

または

$ export CFLAGS="-arch x86_64 -arch arm64"
$ export LDFLAGS="-arch x86_64 -arch arm64"
$ ./configure

makeしてfileでUniversal Binaryになっているのを確認して実行します。

$ make
$ src/test
src/test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
src/test (for architecture x86_64): Mach-O 64-bit executable x86_64
src/test (for architecture arm64):  Mach-O 64-bit executable arm64
$ src/test
arm64
$ arch -x86_64 src/test
i386

~/Downloads/に戻ります。

$ cd ..

libpng

autotoolsを使用するオープンソースのライブラリの例としてlibpngをUniversal Binaryでビルドして、サンプルプログラムをリンクして利用してみます。

http://www.libpng.org/pub/png/libpng.html
よりlibpng-1.6.37.tar.xzをダウンロードして展開します。

$ tar xvfJ libpng-1.6.37.tar.xz

libpngのARMバイナリビルド

まず普通にビルドして/usr/local/opt/libpng-arm64以下にインストールします。

$ cd libpng-1.6.37
./configure --prefix=/usr/local/opt/libpng-arm64
make
make install
cd ..

ARMバイナリとしてビルドされます。

$ file /usr/local/opt/libpng-arm64/lib/libpng.dylib 
/usr/local/opt/libpng-arm64/lib/libpng.dylib: Mach-O 64-bit dynamically linked shared library arm64

http://zarb.org/~gc/html/libpng.html
にあるコードをpngtest.cとして作成しpngtestとしてビルドします。pngファイルの画素ごとに赤を0緑を青の値にしてpngファイルに書き込むプログラムです。入力画像は適当な画像を用意してtest1.pngとしてください。出力ファイルをtest2.pngとします。

ARMバイナリとしてビルドしARMライブラリのlibpngをリンクしています。

clang -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-arm64/include -L/usr/local/opt/libpng-arm64/lib
 file pngtest
pngtest: Mach-O 64-bit executable arm64
./pngtest test1.png test2.png

x86_64バイナリはうまくリンクできずエラーになります。libpngがARMバイナリだからです。

$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-arm64/include -L/usr/local/opt/libpng-arm64/lib
(略)
Undefined symbols for architecture x86_64:
  "_png_create_info_struct", referenced from:
(略)

libpngのx86_64バイナリビルド

次にlibpngをx86_64バイナリとしてビルドしましょう。/usr/local/opt/libpng-x86_64にインストールします。CFLAGSとLDFLAGSに-arch x86_64を指定することでx86_64バイナリとしてビルドできます。

$ cd libpng-1.6.37
$ make clean
$ env CFLAGS="-arch x86_64" LDFLAGS="-arch x86_64" ./configure --prefix=/usr/local/opt/libpng-x86_64
$ make
$ make install
$ cd ..
% file /usr/local/opt/libpng-x86_64/lib/libpng.dylib
/usr/local/opt/libpng-x86_64/lib/libpng.dylib: Mach-O 64-bit dynamically linked shared library x86_64

pngtest.cをx86_64バイナリとしてビルドしてx86_64バイナリのlibpngとリンクします。
正常に実行できます。

$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-x86_64/include -L/usr/local/opt/libpng-x86_64/lib

$ file pngtest
pngtest: Mach-O 64-bit executable x86_64
$./pngtest test1.png test2.png

libpngのUniversal Binaryビルド

libpngをUniversal Binaryとしてビルドします。CFLAGSとLDFLAGSに-arch x86_64 -arch arm64を指定してARMとx86_64両対応でビルドします。

$ cd libpng-1.6.37
$ make clean
$ env CFLAGS="-arch x86_64 -arch arm64" LDFLAGS="-arch x86_64 -arch arm64" ./configure --prefix=/usr/local/opt/libpng-universal
$ make 
$ make install
$ cd ..

ARMとx86_64対応Universal Binaryとしてビルドされています。

$ file /usr/local/opt/libpng-universal/lib/libpng.dylib
/usr/local/opt/libpng-universal/lib/libpng.dylib: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit dynamically linked shared library x86_64] [arm64:Mach-O 64-bit dynamically linked shared library arm64]
/usr/local/opt/libpng-universal/lib/libpng.dylib (for architecture x86_64): Mach-O 64-bit dynamically linked shared library x86_64
/usr/local/opt/libpng-universal/lib/libpng.dylib (for architecture arm64):  Mach-O 64-bit dynamically linked shared library arm64

まず普通にpngtest.cをビルドしてリンクしてみます。

$ clang -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib

ARMバイナリとしてリンクでき正常に実行できます。

$ file pngtest
pngtest: Mach-O 64-bit executable arm64
$ ./pngtest test1.png test2.png

clangに-arch x86_64を与えてx86_64としてpngtest.cをビルドしてリンクするとx86_64バイナリとしてリンクでき正常に実行できます。

$ clang -arch x86_64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib
$ file pngtest
pngtest: Mach-O 64-bit executable x86_64
$ ./pngtest test1.png test2.png

さらにclangに-arch x86_64 -arch arm64を与えればUniversal Binaryとしてpngtest.cをビルドしてリンクでき実行できます。

$ clang -arch x86_64 -arch arm64 -o pngtest pngtest.c -lpng -I/usr/local/opt/libpng-universal/include -L/usr/local/opt/libpng-universal/lib
$ file pngtest 
pngtest: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
pngtest (for architecture x86_64):  Mach-O 64-bit executable x86_64
pngtest (for architecture arm64):   Mach-O 64-bit executable arm64
$ ./pngtest test1.png test2.png

CMakeの場合

CMakeは様々な環境でビルドできるようにするための開発ツールです。UnixのMakefile、macOSのXcode、WindowsのVisual Studioなどでビルドに必要なファイルを自動生成できます。

自作のCMake対応プログラムの通常ビルド

test.cをCMakeに対応させます。

cmaketest以下にtest.cとCMakeLists.txtを作成します。

$ mkdir cmaketest
$ cd cmaketest

test.cは上記をコピーしてください。

$ cp ../test.c .

CMakeLists.txtは

cmake_minimum_required(VERSION 2.8)
project(test_cmake C)
add_executable(test test.c)

とします。

build以下でcmakeでMakefileを作成してビルドします。

$ mkdir build
$ cd build
$ cmake ..
$ make
$ file test
test: Mach-O 64-bit executable arm64
$ ./test
arm64
$ cd ..

自作のCMake対応プログラムのx86_64ビルド

CMAKE_OSX_ARCHITECTURESにx86_64を指定するとclangに-arch x86_64を指定するのと同じ意味となりx86_64バイナリをビルドできます。build-x86_64以下でビルドします。

$ mkdir build-x86_64
$ cd build-x86_64 
$ env CMAKE_OSX_ARCHITECTURES=x86_64 cmake ..
$ make
$ file test 
test: Mach-O 64-bit executable x86_64
$ ./test
i386
$ cd ..

自作のCMake対応プログラムのUniversal Binaryビルド

CMAKE_OSX_ARCHITECTURESにx86_64;arm64を指定するとclangに-arch x86_64 -arch arm64と同じ意味になりUniversal Binaryとしてビルドできます。build-universal以下でビルドします。

$ mkdir build-universal
$ cd build-universal 
$ env CMAKE_OSX_ARCHITECTURES="x86_64;arm64" cmake ..
$ file test 
test: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture x86_64): Mach-O 64-bit executable x86_64
test (for architecture arm64):  Mach-O 64-bit executable arm64

ARMとしてもx86_64としても実行できます。

$ ./test 
arm64
$ arch -x86_64 ./test 
i386

上に戻ります。

cd ..

i386とx86_64の場合

32bit i386とのUniversal Binaryも同様に作れそうなのですがmacOS Catalina以降は32bitバイナリ非対応なのでそのままではビルドできません。

$ clang -arch i386 -o test test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
ld: warning: ignoring file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd, missing required architecture i386 in file /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk/usr/lib/libSystem.tbd (3 slices)
Undefined symbols for architecture i386:
  "_system$UNIX2003", referenced from:
      _main in test-ea1c56.o
ld: symbol(s) not found for architecture i386
clang: error: linker command failed with exit code 1 (use -v to see invocation)

下記のサイトから32bit対応macOS用SDK(MacOSX10.13.sdk.tar.xz)をダウンロードして/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs以下にインストールしてください(10.14でも良さそうですがi386用SDKが入っていない?)。

$ tar xvfJ MacOSX10.13.sdk.tar.xz
$ sudo mv MacOSX10.13.sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs 

MacOSX10.13.sdkを利用したi386とx86_64のUniversal Binaryビルド

clangに-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdkを指定することでMacOSX10.13.sdkを使用してビルドできます。

$ clang -arch i386 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
$ file test
test: Mach-O executable i386

ただし、M1 Macは32bit i386バイナリの実行ができないのでエラーになります。

$ ./test 
zsh: bad CPU type in executable: ./test

32bit i386と64bit x86_64のUniversal Binaryのtest-i386_x86_64としてビルドすればx86_64バイナリとしてM1 Macでも実行できます。

$ clang -arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test-i386_x86_64 test.c
ld: warning: The i386 architecture is deprecated for macOS (remove from the Xcode build setting: ARCHS)
$ file test-i386_x86_64 
test-i386_x86_64: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
test-i386_x86_64 (for architecture i386):   Mach-O executable i386
test-i386_x86_64 (for architecture x86_64): Mach-O 64-bit executable x86_64
$ ./test-i386_x86_64 
i386

逆にMacOSX10.13.sdkはARM非対応なので-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdkを指定してARMバイナリを作ろうとするとエラーになります。

$ clang -arch arm64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk -o test test.c     
In file included from test.c:1:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/stdlib.h:63:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/_types.h:27:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/_types.h:32:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/usr/include/sys/cdefs.h:761:2: error: 
      Unsupported architecture
#error Unsupported architecture
(略)

したがって、ARMとi386とx86_64のUniversal Binaryを作るためにはARMバイナリを別途ビドしてlipoで結合する必要があります。

$ clang -arch arm64 -o test-arm test.c
$ file test-arm 
test-arm: Mach-O 64-bit executable arm64
$ ./test-arm 
arm64

lipoでtest-i386_x86_64とtest-armを結合させてi386、x86_64、ARM対応Universal Binaryのtestを作成します。

$ lipo -create test-arm test-i386_x86_64 -output test
$ file test
test: Mach-O universal binary with 3 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64] [arm64:Mach-O 64-bit executable arm64]
test (for architecture i386):   Mach-O executable i386
test (for architecture x86_64): Mach-O 64-bit executable x86_64
test (for architecture arm64):  Mach-O 64-bit executable arm64
$ ./test
arm64
$ arch -x86_64 ./test  
i386

autotoolsでのi386とx86_64のUniversal Binaryのビルド

CFLAGSとLDFLAGSに-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定すればOKです。autotools-testを再利用します。

$ cd autotools-test
$ make clean
$ export CFLAGS="-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export LDFLAGS="-arch i386 -arch x86_64 -isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ ./configure
$ make 
$ file src/test
src/test: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
src/test (for architecture i386):   Mach-O executable i386
src/test (for architecture x86_64): Mach-O 64-bit executable x86_64
$ src/test
i386
$ cd ..

CMakeを利用したi386とx86_64のUniversal Binaryのビルド

https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-do-i-build-universal-binaries-on-mac-os-x
によるとCMAKE_OSX_SYSROOTに/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定するだけで良さそうですが、CFLAGSとLDFLAGSに-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/を指定しないとダメのようです。CMAKE_OSX_ARCHITECTURESにi386;x86_64を指定してi386とx86_64のUniversal Binaryとしてビルドします。

$ cd cmaketest
$ export CMAKE_OSX_SYSROOT=/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/
$ export CFLAGS="-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export LDFLAGS="-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.13.sdk/"
$ export CMAKE_OSX_ARCHITECTURES="i386;x86_64"
$ mkdir build-i386_x86_64
$ cd build-i386_x86_64
$ cmake ..
$ make
$ file test
test: Mach-O universal binary with 2 architectures: [i386:Mach-O executable i386] [x86_64:Mach-O 64-bit executable x86_64]
test (for architecture i386):   Mach-O executable i386
test (for architecture x86_64): Mach-O 64-bit executable x86_64
$ ./test
i386

まとめ

M1 MacでコマンドラインからUniversal Binaryとしてビルドする様々な手順を示せたと思うので、Universal Binaryのビルドが必要なときに参考にしてみてください。

参考サイト

https://news.mynavi.jp/article/osxhack-268/
https://developer.apple.com/library/archive/technotes/tn2005/tn2137.html
https://gitlab.kitware.com/cmake/community/-/wikis/FAQ#how-do-i-build-universal-binaries-on-mac-os-x
https://www.itmedia.co.jp/enterprise/articles/0712/27/news012_2.html
https://www.webcyou.com/?p=9630

https://zenn.dev/ress/articles/069baf1c305523dfca3d
https://qiita.com/narupo/items/f63b8e768f17ce50f398
https://kamino.hatenablog.com/entry/cmake_tutorial1

11
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
11
7