80

我是 Linux 操作系统的新手。我正在尝试.c使用 makefile 编译文件。必须链接数学库。我的生成文件如下所示:

CC=gcc
CFLAGS=-Wall -lm

all:client

.PHONY: clean
clean:
    rm *~ *.o client

当我运行时make,我收到以下错误:

"undefined reference to rint"

所以它无法链接数学库。

但是当我使用显式编译时

gcc client.c -lm -o client

它成功编译。

那么我应该如何更改我的 makefile 以使其正常工作。我已经尝试添加LDFLAGS=-lm. 但我得到同样的错误。

我还应该补充一点,当我运行时make,它会扩展为

gcc -Wall -lm client.c -o client

(请注意,当我最后gcc明确运行-lm时,它可以工作)。

4

3 回答 3

71

您的链接器(ld)显然不喜欢 make 排列 GCC 参数的顺序,因此您必须稍微更改 Makefile:

CC=gcc
CFLAGS=-Wall
LDFLAGS=-lm

.PHONY: all
all: client

.PHONY: clean
clean:
    $(RM) *~ *.o client

OBJECTS=client.o
client: $(OBJECTS)
    $(CC) $(CFLAGS) $(OBJECTS) -o client $(LDFLAGS)

在定义客户端$(LDFLAGS)目标的行中,根据需要更改顺序。

于 2012-11-06T11:29:45.887 回答
55

在更复杂的构建场景中,通常将编译分解为多个阶段,首先进行编译和组装(输出到目标文件),然后将目标文件链接到最终的可执行文件或库中——这样可以避免在编译时重新编译所有目标文件。他们的源文件没有改变。这就是为什么在你放入链接标志-lm时包含它不起作用CFLAGSCFLAGS在编译阶段使用)。

要链接的库的约定是将它们放在其中一个LOADLIBES或中LDLIBS(GNU make 包括两者,但您的里程可能会有所不同):

LDLIBS=-lm

这应该允许您继续使用内置规则,而不必编写自己的链接规则。对于其他品牌,应该有一个输出内置规则的标志(对于 GNU 品牌,这是-p)。如果您的 make 版本没有内置的链接规则(或者如果它没有-l指令的占位符),您需要编写自己的:

client.o: client.c
    $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c -o $@ $<

client: client.o
    $(CC) $(LDFLAGS) $(TARGET_ARCH) $^ $(LOADLIBES) $(LDLIBS) -o $@
于 2012-11-06T15:01:02.370 回答
0

似乎链接标志的顺序在旧版本的 gcc 中不是问题。例如gcc (GCC) 4.4.7 20120313 (Red Hat 4.4.7-16),Centos-6.7 在 inputfile 之前对链接器选项感到满意;但 ubuntu 16.04 的 gccgcc (Ubuntu 5.3.1-14ubuntu2.1) 5.3.1 20160413不允许。

它不仅仅是 gcc 版本,我对发行版有所了解

于 2016-08-10T04:07:09.703 回答