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

有三个文件

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

完结撒花

  • 11
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
iOS 静态库自动打包,使用 shellcmd 脚本如何写 # 获取脚本所在目录 filepath=$(cd "$(dirname "$0")"; pwd)"/" cd $filepath cd .. # 工程target,主要配置这个target即可 targetname="SafeToolSDK" # 工程目录(默认工程目录在脚本目录的上一级目录) projectdir=$(pwd)"/" echo $projectdir # 工程名 projectname="SafeToolSDK.xcodeproj" # lib输出目录 buildDir=$filepath echo $buildDir #lib输出名 libname=$targetname iossdknum=$(xcodebuild -showsdks | grep iphoneos | grep -Eo '[0-9.]+' | sed -n '1p') configurationname="Release" mydir=$filepath$libname"/" rm -rf $mydir mkdir $mydir # arm64 archname="arm64" lib64=$libname"64" echo "archname:$archname" xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir clean xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir libpath=$buildDir"/Release-iphoneos/"$libname".framework" lib64path=$mydir$lib64 mv -f $libpath"/"$libname $lib64path # armv7 archname="armv7" libv7=$libname"v7" echo "archname:$archname" xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir clean xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir libpath=$buildDir"/Release-iphoneos/"$libname".framework" libv7path=$mydir$libv7 mv -f $libpath"/"$libname $libv7path # armv7s archname="armv7s" libv7s=$libname"v7s" echo "archname:$archname" xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir clean xcodebuild -project $projectdir$projectname -configuration $configurationname -target $targetname -sdk "iphoneos$iossdknum" -arch $archname BUILD_DIR=$buildDir libpath=$buildDir"/Release-iphoneos/"$libname".framework" lib
### 回答1: Unity 中可以使用 .NET 的 System.Json 命名空间来处理 JSON。您可以使用 JsonDocument 类来解析 JSON 字符串,然后使用 JsonElement 类来访问 JSON 元素。 例如,下面的代码演示了如何解析一个包含数组的 JSON 字符串: ``` string jsonString = "{\"array\":[1,2,3,4,5]}"; JsonDocument json = JsonDocument.Parse(jsonString); JsonElement array = json.RootElement.GetProperty("array"); foreach (var element in array.EnumerateArray()) { Console.WriteLine(element.GetInt32()); } ``` 如果您想将 JSON 序列化为 C# 对象,您可以使用 JsonSerializer 类。例如: ``` string jsonString = "{\"name\":\"John Smith\",\"age\":30,\"city\":\"New York\"}"; Person person = JsonSerializer.Deserialize<Person>(jsonString); Console.WriteLine($"Name: {person.Name}, Age: {person.Age}, City: {person.City}"); ``` 其中,Person 是一个包含 name、age 和 city 属性的类。 希望这能帮到您。 ### 回答2: 在Unity中使用JSON有几个步骤: 1. 创建一个包含JSON数据的字符串。可以手动创建字符串,也可以从外部文件中读取。 2. 创建一个可以将JSON字符串解析为对象的类。可以使用JsonUtility类中的相关方法进行解析。需要确保类的属性与JSON数据的键名完全匹配。 3. 将JSON字符串传递给JsonUtility类的相关方法,将其解析为对象。可以使用JsonUtility.FromJson()方法将JSON字符串解析为对象。解析完成后,可以使用对象的属性来访问JSON中的数据。 4. 将数据从对象中提取出来并在Unity中使用。可以使用对象的属性和方法,来获取和处理JSON数据。 下面是一个简单的示例: 首先,创建一个包含JSON数据的字符串: ``` string json = "{\"name\":\"John\",\"age\":30,\"city\":\"New York\"}"; ``` 然后,创建一个可以将JSON字符串解析为对象的类: ```csharp [System.Serializable] public class Person { public string name; public int age; public string city; } ``` 接下来,将JSON字符串解析为对象: ```csharp Person person = JsonUtility.FromJson<Person>(json); ``` 最后,可以通过对象的属性来访问JSON中的数据: ```csharp Debug.Log("Name: " + person.name); Debug.Log("Age: " + person.age); Debug.Log("City: " + person.city); ``` 这样就可以在Unity中使用JSON数据了。需要注意的是,Unity的JsonUtility类对于复杂的JSON结构或嵌套对象可能不够灵活,如果遇到这种情况,可以考虑使用第三方库如Newtonsoft.Json来解析和处理JSON。 ### 回答3: Unity中使用JSON可以通过Unity自带的JsonUtility类来实现。 首先,需要引入命名空间 `using System.IO;` 和 `using UnityEngine;`。 然后,我们可以使用JsonUtility类的静态方法`JsonUtility.FromJson()`来将JSON字符串转换为对象,或使用`JsonUtility.ToJson()`将对象转换为JSON字符串。 例如,假设我们有一个名为`Player`的类,它有两个属性`name`和`score`: ```csharp [System.Serializable] public class Player { public string name; public int score; } ``` 我们可以将一个`Player`对象转换为JSON字符串: ```csharp Player player = new Player(); player.name = "Tom"; player.score = 100; string json = JsonUtility.ToJson(player); ``` 我们也可以将JSON字符串转换为`Player`对象: ```csharp string json = "{\"name\":\"Tom\",\"score\":100}"; Player player = JsonUtility.FromJson<Player>(json); ``` 注意,在使用`JsonUtility.FromJson()`方法时,需要确保类的属性名与JSON字符串中的键名一致。 此外,还可以使用`JsonUtility.FromJsonOverwrite()`方法将JSON字符串的值直接覆盖到已存在的对象上,而不是创建新的对象。 综上所述,Unity中使用JSON,我们可以通过JsonUtility类来进行对象与JSON字符串的相互转换。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值