关于静态库的嵌套使用问题

有三个文件

// 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

完结撒花

  • 16
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值