如何在GCC中只链接LIB一次?

如何在GCC中只链接LIB一次?,gcc,linker,Gcc,Linker,请原谅我的问题,我是GCC的初学者。我有一个框架项目,其中包含多个子组件的源代码 结构如下: Framework/ makefile //Master makefile in root Component1/ src/ bin/ makefile Component2/ src/ bin/ makefile ... ... ... ComponentN/

请原谅我的问题,我是GCC的初学者。我有一个框架项目,其中包含多个子组件的源代码

结构如下:

Framework/
makefile //Master makefile in root
    Component1/
       src/
       bin/
       makefile
    Component2/
       src/
       bin/
       makefile
    ...
    ...
    ...
    ComponentN/
       src/
       bin/
       makefile
现在,ComponentN/每个目录中的每个makefile将在各自的src/中编译代码,并将.o输出到bin/目录

但是,根makefile递归搜索所有.o文件,并将它们链接到一个名为“framework”的可执行文件中

问题:

对于glib、gdbus、gio等代码依赖项,在每个组件项目中创建.o对象时,我必须将它们链接一次

另外,在根级别将所有.o链接到一个可执行文件时,我必须再次链接依赖项

为什么我要做两次?我对理解内部力学感兴趣

根据要求,我将生成*.o文件的单个组件库的makefile放入其中

CC = gcc
CFLAGS = -g3
LIBS = `pkg-config --cflags --libs glib-2.0`
BINDIR = bin
OUTOBJ = $(addprefix $(BINDIR)/, objex.o)

$(BINDIR)/%.o : %.c
               $(CC) -c $< $(CFLAGS) -o $@ $(LIBS)

all: $(OUTOBJ)

$(OUTOBJ): | $(BINDIR)

$(BINDIR):
          mkdir $(BINDIR)

.PHONY: clean
clean:
      rm bin/*

对象文件(
.o
)由编译命令创建,例如

gcc -c -o foo.o foo.c ...
g++ -c -o baz.o baz.cpp ...
-c
表示编译;不要链接。在创建 对象文件由编译器生成。添加到编译中的任何链接选项 命令,例如

gcc -c -o foo.o foo.c -L/my/libs -lbar -lgum
这些都被忽略了

链接选项由创建程序或共享/动态链接的链接命令执行 库,通过将对象文件和库链接在一起,例如

gcc -o prog foo.o baz.o -L/my/libs -lbar -lgum
gcc -shared -o libfoobaz.so foo.o baz.o -L/my/libs -lbar -lgum
因此:

对于glib、gdbus、gio等代码依赖项,在每个组件项目中创建.o对象时,我必须将它们链接一次

不,你不能,你也不能

以后

看到makefile的问题,很清楚如何消除它 编译配方中的
$(LIBS)
引用,以及阻止您的原因。makefile定义了:

LIBS = `pkg-config --cflags --libs glib-2.0`
这是一个错误。这使得
$(LIBS)
扩展到 命令:

这是一个包含所需编译选项的单个字符串 用于编译
#包含
-s的
glib-2.0
API的源代码(考虑到
-cflags
) 以及链接程序或共享库所需的链接选项 针对
libglib-2.0
(由于
--libs
)。在我的系统上,即:

$ pkg-config --cflags --libs glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0
其中仅编译选项将通过以下方式输出:

$ pkg-config --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
$ pkg-config --libs glib-2.0
-lglib-2.0
仅联动选项将通过以下方式输出:

$ pkg-config --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
$ pkg-config --libs glib-2.0
-lglib-2.0
但因为这两组选项只能通过扩展一起使用 在
$(LIBS)
中,如果不传递 链接选项
-lglib-2.0
,它是冗余的,被忽略

由于您的make工具显然是GNU make,因此makefile(顺便说一句,没有那么糟糕!)最好写为:

Makefile

CC := gcc
CFLAGS := -g3 $(shell pkg-config --cflags glib-2.0)
BINDIR := bin
SRCS := objex.c
OUTOBJ := $(addprefix $(BINDIR)/, $(SRCS:.c=.o))

.PHONY: all clean

all: $(OUTOBJ)

$(BINDIR)/%.o : %.c
    $(CC) -c $< $(CFLAGS) -o $@

$(OUTOBJ): | $(BINDIR)

$(BINDIR):
    mkdir -p $(BINDIR)

clean:
    $(RM) $(OUTOBJ)
请注意其他一些改进:-

在适用的情况下优先使用即时扩展(
:=
),而不是不必要的扩展 递归扩展(
=
)。看

通过make-
$(shell命令)
-使用直接shell替换,而不是在 配方执行。看

all
,比如
clean
是一个 您需要告诉make它是,以避免诱杀陷阱,在诱杀陷阱中,某些东西创建了一个名为
all
in的文件 项目目录在您没有注意到的情况下神秘地停止检测它要做的任何工作

使用您的
clean
receipe:

clean:
      rm bin/*
makeclean
如果在成功构建之后运行,则将失败。食谱 使用gnumake预定义的delete宏替换为
$(RM)$(OUTOBJ)
,该宏 不会失败的

最后,请记住,您的链接配方无论在哪里,都需要glib-2.0的库选项, 您应该在其makefile中提供:

LIBS := $(shell pkg-config --libs glib-2.0) # ...and any more library options required
用于类似以下配方的配方:

prog: $(OBJS)
    $(CC) -o $@ $(LDFLAGS) $^ $(LIBS)

[1] 严格地说,预处理器选项应该出现在
CPPFLAGS
(C预处理器标志),不要与
CXXFLAGS
(C++编译选项)混淆

[2] 严格来说,定义中应显示库以外的链接选项 对象文件(
.o
)由编译命令创建,例如

gcc -c -o foo.o foo.c ...
g++ -c -o baz.o baz.cpp ...
-c
表示编译;不要链接。在创建 对象文件由编译器生成。添加到编译中的任何链接选项 命令,例如

gcc -c -o foo.o foo.c -L/my/libs -lbar -lgum
这些都被忽略了

链接选项由创建程序或共享/动态链接的链接命令执行 库,通过将对象文件和库链接在一起,例如

gcc -o prog foo.o baz.o -L/my/libs -lbar -lgum
gcc -shared -o libfoobaz.so foo.o baz.o -L/my/libs -lbar -lgum
因此:

对于glib、gdbus、gio等代码依赖项,在每个组件项目中创建.o对象时,我必须将它们链接一次

不,你不能,你也不能

以后

看到makefile的问题,很清楚如何消除它 编译配方中的
$(LIBS)
引用,以及阻止您的原因。makefile定义了:

LIBS = `pkg-config --cflags --libs glib-2.0`
这是一个错误。这使得
$(LIBS)
扩展到 命令:

这是一个包含所需编译选项的单个字符串 用于编译
#包含
-s的
glib-2.0
API的源代码(考虑到
-cflags
) 以及链接程序或共享库所需的链接选项 针对
libglib-2.0
(由于
--libs
)。在我的系统上,即:

$ pkg-config --cflags --libs glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -lglib-2.0
其中仅编译选项将通过以下方式输出:

$ pkg-config --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
$ pkg-config --libs glib-2.0
-lglib-2.0
仅联动选项将通过以下方式输出:

$ pkg-config --cflags glib-2.0
-I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include
$ pkg-config --libs glib-2.0
-lglib-2.0
但因为这两组选项只能通过扩展一起使用 在
$(LIBS)
中,如果不传递 链接选项
-lglib-2.0
,它是冗余的,被忽略

由于您的make工具显然是GNU make,因此makefile(顺便说一句,没有那么糟糕!)最好写为:

<