CMake: ターゲットプロパティ "VISIBILITY_INLINES_HIDDEN" を使ってインライン関数のシンボルを隠す方法
VISIBILITY_INLINES_HIDDEN
は、CMake のターゲットプロパティであり、インライン関数のシンボルを隠すためのコンパイラフラグ (-fvisibility-inlines-hidden
など) を使用するか否かを決定します。これは、ライブラリやエクスポートを持つ実行ファイルにのみ影響を与えます。
影響
このプロパティが ON
に設定されている場合、CMake はコンパイル時に -fvisibility-inlines-hidden
フラグを指定します。これにより、インライン関数のシンボルがリンカから隠され、他のモジュールからのアクセスが制限されます。これは、コードのサイズを小さくし、リンカエラーを回避するのに役立ちます。
設定方法
以下の例のように、set_target_properties
コマンドを使用して VISIBILITY_INLINES_HIDDEN
プロパティを設定できます。
add_library(MY_LIB ${MY_SOURCES})
set_target_properties(MY_LIB PROPERTIES C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
上記の例では、MY_LIB
ターゲットに対して VISIBILITY_INLINES_HIDDEN
プロパティが ON
に設定されています。
- このプロパティは、GCC、Clang、Visual Studioなどの多くのコンパイラでサポートされています。
VISIBILITY_INLINES_HIDDEN
プロパティは、CMake 3.0 以降でのみ使用できます。
例
以下の例は、VISIBILITY_INLINES_HIDDEN
プロパティを使用してインライン関数のシンボルを隠す方法を示しています。
cmake_minimum_required(VERSION 3.0)
project(MY_PROJECT)
add_library(MY_LIB ${MY_SOURCES})
set_target_properties(MY_LIB PROPERTIES C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
add_executable(MY_APP ${MY_APP_SOURCES})
target_link_libraries(MY_APP MY_LIB)
上記の例では、MY_LIB
ライブラリのインライン関数のシンボルは隠され、MY_APP
アプリケーションからはアクセスできません。
ライブラリとアプリケーションの例
この例では、mylib.c
というソースファイルでインライン関数を定義し、mylib.so
という共有ライブラリと myapp
という実行ファイルを作成します。ライブラリのインライン関数のシンボルは隠され、実行ファイルからはアクセスできません。
ソースファイル
// mylib.c
#include <stdio.h>
inline void my_inline_function() {
printf("This is an inline function.\n");
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(MY_PROJECT)
add_library(MY_LIB mylib.c)
set_target_properties(MY_LIB PROPERTIES C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
add_executable(MY_APP myapp.c)
target_link_libraries(MY_APP MY_LIB)
myapp.c
#include <stdio.h>
#include "mylib.h"
int main() {
non_inline_function(); // This is OK
// my_inline_function(); // This will cause a linker error
return 0;
}
このコードを実行すると、以下の出力が得られます。
This is not an inline function.
my_inline_function
はインライン関数なので、実行ファイルからは直接呼び出すことができません。
この例では、mylib1.c
と mylib2.c
というソースファイルでインライン関数を定義し、それぞれ mylib1.so
と mylib2.so
という共有ライブラリを作成します。mylib1.so
のインライン関数のシンボルは隠され、mylib2.so
のインライン関数のシンボルは隠されません。
ソースファイル
// mylib1.c
#include <stdio.h>
inline void mylib1_inline_function() {
printf("This is an inline function in mylib1.\n");
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
// mylib2.c
#include <stdio.h>
inline void mylib2_inline_function() {
printf("This is an inline function in mylib2.\n");
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
CMakeLists.txt
cmake_minimum_required(VERSION 3.0)
project(MY_PROJECT)
add_library(MY_LIB1 mylib1.c)
set_target_properties(MY_LIB1 PROPERTIES C_VISIBILITY_PRESET hidden VISIBILITY_INLINES_HIDDEN ON)
add_library(MY_LIB2 mylib2.c)
add_executable(MY_APP myapp.c)
target_link_libraries(MY_APP MY_LIB1 MY_LIB2)
myapp.c
#include <stdio.h>
#include "mylib1.h"
#include "mylib2.h"
int main() {
non_inline_function(); // This is OK
mylib1_inline_function(); // This will cause a linker error
mylib2_inline_function(); // This is OK
return 0;
}
This is not an inline function.
This is an inline function in mylib2.
mylib1.so
のインライン関数は隠されているため、myapp
からは直接呼び出すことができません。一方、mylib2.so
のインライン関数は隠されていないため、myapp
から直接呼び出すことができます。
static キーワード
インライン関数を static
キーワードで宣言することで、その関数のシンボルをファイルスコープに限定することができます。これは、インライン関数へのアクセスをそのファイル内にのみ制限するため、最も単純で効果的な方法です。
利点
- コンパイル時にシンボルを隠すため、オーバーヘッドが少ない
- シンプルで理解しやすい
欠点
- インライン関数が他のファイルから呼び出される可能性がある場合、意図せずシンボルが公開されてしまう可能性がある
- ライブラリや共有オブジェクトでは使用できない
例
// mylib.c
static inline void my_inline_function() {
printf("This is an inline function.\n");
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
匿名名前空間
利点
- ライブラリや共有オブジェクトで使用できる
欠点
- コンパイル時にシンボルを隠すため、オーバーヘッドが少ない
static
キーワードよりも複雑で理解しにくい
例
// mylib.c
namespace {
inline void my_inline_function() {
printf("This is an inline function.\n");
}
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
マクロ
マクロを使用して、インライン関数を呼び出すためのラッパーを作成することができます。この方法は、インライン関数のシンボルを完全に隠すことができ、コンパイラによる最適化を抑制することができます。
利点
- コンパイラによる最適化を抑制できる
- インライン関数のシンボルを完全に隠すことができる
欠点
- マクロのオーバーヘッドが発生する
- 複雑で理解しにくい
例
// mylib.c
#define MY_INLINE_FUNCTION() \
inline void { \
printf("This is an inline function.\n"); \
}
void non_inline_function() {
printf("This is not an inline function.\n");
}
int main() {
MY_INLINE_FUNCTION();
return 0;
}
コンパイラ固有のオプション
多くのコンパイラは、インライン関数のシンボルを隠すためのオプションを提供しています。これらのオプションは、CMake の VISIBILITY_INLINES_HIDDEN
プロパティよりも詳細な制御を提供することができます。
利点
- 詳細な制御を提供できる
欠点
- CMake との互換性がない場合がある
- コンパイラごとに異なるオプションがある
例
- Visual Studio:
/visibility:hidden
- Clang:
-fvisibility=hidden
- GCC:
-fvisibility=hidden
これらの代替方法のいずれを選択するかは、それぞれの状況や要件によって異なります。単純で効果的な方法が必要な場合は、static
キーワードが最適です。より柔軟性が必要な場合は、匿名名前空間を使用することができます。インライン関数のシンボルを完全に隠す必要がある場合は、マクロを使用することができます。コンパイラ固有のオプションを使用すると、より詳細な制御が可能になりますが、CMake との互換性がない場合があります。