有三个文件
// fun1.c内容如下
#include <stdio.h>
int func1() {
printf("func1\n");
return 0;
}
// fun2.c内容如下
#include <stdio.h>
int func1();
int func2() {
func1();
printf("func2\n");
return 0;
}
// main.c内容如下
int func2();
int main() {
func2();
return 0;
}
明显可以看出,main函数依赖于fun2,而fun2依赖与fun1,当我们使用以下命令编译
gcc -o exe fun1.c fun2.c main.c
结果是成功的。
但是我们玩的花一点
将fun1.c 编译为静态库lib1.a,再和fun2.c一起编译为lib2.a,再使用lib2.a和main.c编译为exe
gcc -c fun1.c -o fun1.o
ar rcs lib1.a fun1.o
gcc -c fun2.c -o fun2.o
ar rcs lib2.a lib1.a fun2.o
gcc -c main.c -o main.o
gcc -o exe main.o lib2.a
会报错
/usr/bin/ld: lib2.a(fun2.o): in function `func2':
fun2.c:(.text+0xe): undefined reference to `func1'
collect2: error: ld returned 1 exit status
原因在于这句
ar rcs lib2.a lib1.a fun2.o
实际上和
ar rcs lib2.a fun2.o
毫无区别
因为
ar rcs lib2.a lib1.a fun2.o 实际上是将lib1.a作为一个整体添加到了lib2.a中,而不是将lib1.a内部的fun1.o单独提取出来。这意味着lib2.a中包含了lib1.a的整个归档,而不是fun1.o和fun2.o作为单独的对象文件。因此,当尝试链接main.o时,链接器首先在lib2.a中查找func1,但是由于lib1.a内部的fun1.o没有被单独提取出来,链接器无法找到func1的定义。
以上是AI的回答,总而言之,编译器无法链接lib2.a内部的lib1.a,它只能链接lib2.a内部.o文件。
所以可以改为下面的代码
ar rcs lib1.a fun1.o
ar rcs lib2.a fun2.o
gcc -o exe main.o lib2.a lib1.a
有人说,我就是想让 lib2.a 包含 lib1.a 怎么办,那就
ar rcs lib2.a fun1.o fun2.o
又有人问,如果只有lib1.a,没有源代码,又想让ib2.a 包含 lib1.a 怎么办,那就
ar x lib1.a
会生成fun1.o
然后
ar rcs lib2.a fun1.o fun2.o
接上一篇Makefile的内容,把静态库嵌套的知识合并进去
# linux下使用/bin/dash,echo -e 会将 -e 输出,windows下可删除此行
SHELL = /bin/bash
# 设置中间文件路径和目标文件名称
BUILD_DIR := ./build/
# TARGET := ./execute
TARGET := ./libtest.a
# 设置编译工具链路径和编译器路径
TOOLCHAIN_DIR := /usr/
COMPILER_PATH := $(TOOLCHAIN_DIR)bin/
# 设置编译器命令和标志
CC := $(COMPILER_PATH)gcc
CX := $(COMPILER_PATH)g++
LD := $(COMPILER_PATH)g++
SZ := $(COMPILER_PATH)size
AR := $(COMPILER_PATH)ar
OBJCOPY := $(COMPILER_PATH)objcopy
CC_MARK := .xc
CX_MARK := .xc++
CC_FLAG := -xc -g
CX_FLAG := -xc++ -g
LD_FLAG :=
# 设置自定义源文件列表
HEAD_PATH := -I/root/workspace/code/third_party/jansson/include/
LIB_PATH :=
LIB_FLAG :=
SRC_LIB := /root/workspace/code/third_party/jansson/lib/libjansson.a
SRC_CC :=
SRC_CX :=
# 设置自动搜索源文件列表
HEAD_TYPE := .h .hpp .hh
LIB_TYPE := .a .so
CC_TYPE := .c
CX_TYPE := .cpp
EXCLUDE_FILES :=
HEAD_TYPE_SIFT := $(patsubst .%,%,$(subst $(empty) .,\|,$(HEAD_TYPE)))
LIB_TYPE_SIFT := $(patsubst .%,%,$(subst $(empty) .,\|,$(LIB_TYPE)))
CC_TYPE_SIFT := $(patsubst .%,%,$(subst $(empty) .,\|,$(CC_TYPE)))
CX_TYPE_SIFT := $(patsubst .%,%,$(subst $(empty) .,\|,$(CX_TYPE)))
LOCAL_HEAD := $(shell find . -type f -regex ".*\.\($(HEAD_TYPE_SIFT)\)" -printf "%P ")
LOCAL_LIB := $(shell find . -type f -regex ".*\.\($(LIB_TYPE_SIFT)\)" -printf "%P ")
LOCAL_CC := $(shell find . -type f -regex ".*\.\($(CC_TYPE_SIFT)\)" -printf "%P ")
LOCAL_CX := $(shell find . -type f -regex ".*\.\($(CX_TYPE_SIFT)\)" -printf "%P ")
HEAD_PATH += $(addprefix -I,$(sort $(dir $(filter-out $(EXCLUDE_FILES),$(LOCAL_HEAD)))))
SRC_LIB += $(filter-out $(EXCLUDE_FILES),$(LOCAL_LIB))
SRC_CC += $(filter-out $(EXCLUDE_FILES),$(LOCAL_CC))
SRC_CX += $(filter-out $(EXCLUDE_FILES),$(LOCAL_CX))
# 生成中间文件列表
OBJ_CC := $(addprefix $(BUILD_DIR),$(notdir $(SRC_CC:%=%$(CC_MARK).o)))
OBJ_CX := $(addprefix $(BUILD_DIR),$(notdir $(SRC_CX:%=%$(CX_MARK).o)))
# 设置源文件查找路径
vpath % $(sort $(dir $(SRC_CC))) $(sort $(dir $(SRC_CX)))
# 定义all依赖
all : $(TARGET)
# @echo " CHECK $<"
# @$(SZ) $<
# 包含依赖文件
-include $(wildcard $(BUILD_DIR)*.d)
# 定义编译和链接命令和规则
$(TARGET) : $(OBJ_CC) $(OBJ_CX) $(SRC_LIB)
@echo " LN $^ -> $@"
#@$(LD) $(LD_FLAG) -o $@ $^ $(LIB_PATH) $(LIB_FLAG) $(SRC_LIB)
@$(AR) x $(SRC_LIB) --output=$(BUILD_DIR)
@$(AR) rcs $@ $(BUILD_DIR)*.o
# 定义隐式规则
$(BUILD_DIR)%$(CC_MARK).o : % Makefile | $(BUILD_DIR)
@echo " CC $<"
@$(CC) $(CC_FLAG) $(HEAD_PATH) -MMD -MP -MF"$(@:%.o=%.d)" -c $< -o $@
$(BUILD_DIR)%$(CX_MARK).o : % Makefile | $(BUILD_DIR)
@echo " CX $<"
@$(CX) $(CX_FLAG) $(HEAD_PATH) -MMD -MP -MF"$(@:%.o=%.d)" -c $< -o $@
$(BUILD_DIR) :
@echo " MK $@"
@mkdir $@
# 定义生成compile_commands.json文件的规则
json: $(SRC_CC) $(SRC_CX) Makefile
@echo "Generating compile_commands.json"
@rm -f compile_commands.json
@echo "[" > compile_commands.json
@for file in $(SRC_CC); do \
compile_cmd="$(CC) $(CC_FLAG) $(HEAD_PATH) -c $${file} -o $${file}$(CC_MARK).o" \
command_json=" { \"arguments\": [ \"$$compile_cmd\" ], \"directory\": \"${PWD}\", \"file\": \"$$file\" },"; \
echo -e "$$command_json" >> compile_commands.json ; \
done
@for file in $(SRC_CX); do \
compile_cmd="$(CX) $(CX_FLAG) $(HEAD_PATH) -c $${file} -o $${file}$(CX_MARK).o" \
command_json=" { \"arguments\": [ \"$$compile_cmd\" ], \"directory\": \"${PWD}\", \"file\": \"$$file\" },"; \
echo -e "$$command_json" >> compile_commands.json ; \
done
@sed -i '$$ s/,$$/\n]/' compile_commands.json
# 定义清理规则
clean:
rm -fR $(BUILD_DIR) $(TARGET)
.PHONY: all clean json
完结撒花