代码按预期编译,但不知何故,二进制文件不知道库在哪里。
❯ ldd myteams_cli
linux-vdso.so.1 (0x00007ffcbc1b4000)
libmyteams.so => not found
libc.so.6 => /usr/lib/libc.so.6 (0x00007414e0bf3000)
/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (0x00007414e0e1d000)
这是Makefile,我知道它找到了库,因为当我故意拼错库名称时它无法编译:
CFLAGS = -Wall -Wextra -Werror -L../libs/myteams -lmyteams
NAME = myteams_cli
SRC = src/main.c \
OBJ_DIR = obj
OBJ = $(SRC:%.c=$(OBJ_DIR)/%.o)
$(OBJ_DIR)/%.o: %.c
@mkdir -p $(@D)
@$(CC) $(CFLAGS) -c $< -o $@
all: $(NAME)
$(NAME): $(OBJ)
@mkdir -p $(@D)
gcc -o $(NAME) $(OBJ) $(CFLAGS)
clean:
rm -f $(OBJ_DIR)/*.o
rm -rf $(OBJ_DIR)/src
fclean: clean
rm -f $(NAME)
re: fclean all
此外,项目编译后,二进制文件必须立即可执行。每次我想启动程序时,我不能只将库路径添加到我的
LD_LIBRARY_PATH
环境变量中(顺便说一下,它可以工作),也不能将库复制到 /usr/lib
,因为这需要触发 Makefile 与 sudo
。
链接器的
-L
选项设置 链接时搜索路径。这仅在链接程序时有效,它不会更改运行时搜索路径,这是程序在运行时查找库的位置。正如评论中提到的,您想使用链接器选项-rpath
。大多数编译器不知道该选项,因此您必须使用(对于 GCC 和 clang)-Wl,-rpath
。
如果您在网上搜索“设置运行时搜索路径”和/或“rpath”,您会发现很多有用的信息。
在你的 makefile 中,你确实需要区分 linker 选项和 compiler 选项;像
CFLAGS
这样将它们全部放入同一个变量中是不好的。 CFLAGS
(按照惯例)是编译器标志。您应该使用 LDFLAGS
作为链接器标志,使用 LDLIBS
作为要链接的库(按照惯例)。所以尝试这样的事情:
CFLAGS = -Wall -Wextra -Werror
LDFLAGS = -L../libs/myteams -Wl,-rpath=../libs/myteams
LDLIBS = -lmyteams
...
$(NAME): $(OBJ)
@mkdir -p $(@D)
gcc -o $(NAME) $(CFLAGS) $(LDFLAGS) $(OBJ) $(LDLIBS)
(通常我们也会将编译器标志传递给链接器,以防万一)