完整的示例源代码:
https://github.com/Kleenelan/makefile-header-file-trigger.git
1,文件布局
2,头文件重构建
Makefile
TARGET := libicarithmetic.so
DEBUG_FLAGS := -O3
HEADER_FLAGS := -MD -MF $*.d -MP
all: $(TARGET)
SRC_C := \
src/add.c \
src/circ.c \
src/div.c \
src/mul.c \
src/sub.c
OBJ_C := $(SRC_C:.c=.c.o)
DEP_C := $(SRC_C:.c=.d)
CPP_FLAGS := $(DEBUG_FLAGS) -fPIC
INC := -I./include/internal
LD_FLAGS :=
#CXX := gcc
-include $(DEP_C)
%.c.o: %.c
$(CXX) $(CPP_FLAGS) $(INC) $< -c -o $@ -MD -MF $*.d -MP
$(TARGET): $(OBJ_C)
$(CXX) -shared $^ -o $@
.PHONY: clean
clean:
rm -rf $(OBJ_C) $(TARGET) $(DEP_C)
#$(SRC_C:.c=.d)
3,主要内容
绿色行增加的部分
4,解释
# 注释: $* 表示目标模式中 '%' 及其之前的部分.如果目标是 'dir/a.foo.b',
# 并且目标的模式为 'a.%.b',那么 '$*' 的值就是 'dir/a.foo'。
# 如果目标中没有模式的定义,那么 '$*' 就不能被推导出;
# 但是,如果目标文件是 make 所识别的,那么 '$*' 就是除了后缀的那一部分。
# 例如: 目标是 'foo.c',因为 '.c' 是 make 所能识别的后缀名,
# 所以 '$*' 的值就是 'foo',这个特性是 GNU make 的。
-MD生成依赖文件;
-MT指定依赖文件中目标文件的名称;
-MF指定生成的依赖文件的路径和名称;
这样,构建系统可以利用.d文件来跟踪源文件和头文件之间的依赖关系,从而在头文件更新时仅重新编译受影响的源文件,提高构建效率。
5,效果
修改头文件后,触发重新构建
6,符号表优化
仅 export API 并隐藏其他函数
TARGET := libicarithmetic.so
DEBUG_FLAGS := -O3
HEADER_FLAGS := -MD -MF $*.d -MP
all: $(TARGET)
SRC_C := \
src/add.c \
src/circ.c \
src/div.c \
src/mul.c \
src/sub.c \
src/util.c
OBJ_C := $(SRC_C:.c=.c.o)
DEP_C := $(SRC_C:.c=.d)
CPP_FLAGS := $(DEBUG_FLAGS) -fPIC -fvisibility=hidden -fvisibility-inlines-hidden -Wno-unused-result -Werror=vla
INC := -I./include/internal
LD_FLAGS :=
#CXX := gcc
-include $(DEP_C)
%.c.o: %.c
$(CXX) $(CPP_FLAGS) $(INC) $< -c -o $@ -MD -MF $*.d -MP
$(TARGET): $(OBJ_C)
$(CXX) -shared $^ -o $@
.PHONY: clean
clean:
rm -rf $(OBJ_C) $(TARGET) $(DEP_C)
#$(SRC_C:.c=.d)
要点:
#define API_ __attribute__((visibility("default")))
API_ float circ_(float r)
{
}
结合编译器标志:
-fvisibility=hidden -fvisibility-inlines-hidden
7,编译选项解释
-Wno-unused-result:忽略未使用的表达式结果警告,这在你调用不需要其返回值的函数时很有用。
-Werror=vla:将变长数组(Variable-Length Array, VLA)视为错误,这有助于避免潜在的栈溢出或不可预测行为问题。
-fvisibility=hidden 和 -fvisibility-inlines-hidden:这两个标志默认隐藏符号,可以减小生成的二进制文件大小并提高加载时间。第一个标志适用于所有符号,第二个标志特别适用于内联函数。