【问题标题】:Makefile, Compiling and LinkingMakefile,编译和链接
【发布时间】:2012-11-19 19:45:42
【问题描述】:

我有一个关于在 Makefile 中编译和链接的问题(也许一般来说)。

我有一个 server.c 文件,它由具有main() 函数的主程序组成。 server.c 包括 rio.c。我有一个名为rio 的模块,它由rio.crio.h 组成。它没有main() 功能。

我有两个问题,如何实际编写 Makefile,以及这样做的最佳实践。

Q1:如何编写 Makefile

我有以下 Makefile:

CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o

all: $(OBJS)
    $(CC) $(CFLAGS) $(OBJS) -o sysstatd

server.o: server.c
    $(CC) $(CFLAGS) -c server.c

rio.o: rio.c rio.h
    $(CC) $(CFLAGS) -c rio.c

clean:
    rm -f *~ *.o sysstatd

我遇到了链接问题。它说我对 C 中使用的所有函数都有多个定义。我不确定这怎么可能,因为 server.c 是用 -c 标志编译的,所以实际上没有任何链接。它应该知道有些函数存在但实际上并没有链接它们,直到all 规则将两个目标文件编译在一起并生成一个包含所有链接的目标文件。

这里有什么问题?

Q2:最佳实践 由于我有一个模块和另一个包含主程序的文件,我应该将主程序server.c 编译为一个单独的模块,然后在all 中一起编译,还是编译 server.c 并添加rio.o 模块在那里?请注意,这仍然会产生与上面相同的链接问题,所以我很确定我的问题出在其他地方。

【问题讨论】:

  • 你在使用任何外部库吗?
  • 是的。但它在我自己的函数上调用错误,说 server.c 首先定义了它们。 server.c 和 rio.h 都导入:stdio.h、stdlib.h、unistd.h 和 errno.h
  • 当您说“server.c 包含 rio.c”时,您的意思是在文件server.c 中,您有类似#include "rio.c" 的行吗?如果是这样,那是错误的方法,也是错误的可能来源;你应该包括rio.h
  • 不仅如此,您还必须在 make 文件中显式链接文件。我很确定您会在-o sysstatd <L> 之后执行此操作,其中<L> 是要链接的库。例如,如果您要链接 libsomelib.a,前提是它在您的 $PATH 中,您可以将 <L> 替换为 -lsomelib
  • @JohnBode 是的,这就是问题所在。这就说得通了。我的 server.o 已经具有 rio.c 功能,因为它包含 rio.c,导致链接错误。如果您将其添加为答案,我会接受。

标签: c compilation linker makefile


【解决方案1】:

你应该稍微修改一下结构:

CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o

all: sysstatd

sysstatd: $(OBJS)
    $(CC) $(CFLAGS) $(OBJS) -o sysstatd

server.o: server.c
    $(CC) $(CFLAGS) -c server.c

rio.o: rio.c rio.h
    $(CC) $(CFLAGS) -c rio.c

clean:
    rm -f *~ *.o sysstatd

不同之处在于,假规则 all 取决于 sysstatd 是否是最新的,而 sysstatd 在目标文件是最新的时是最新的。

现在它只是相当冗长,明确地编写编译操作。使用就足够了:

CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o

all: sysstatd

sysstatd: $(OBJS)
    $(CC) $(CFLAGS) $(OBJS) -o sysstatd

server.o: server.c
rio.o: rio.c rio.h

clean:
    rm -f *~ *.o sysstatd

你也可以辩论:server.c 不使用rio.h 吗?如果是这样,则应列出依赖项。如果不是,为什么rio.h 存在? make 将假定 server.o 依赖于 server.c,因此您不必指定(但它不会对标头做出假设)。您还可以使用宏来防止程序名称重复:

CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
PROG = sysstatd

all: $(PROG)

$(PROG): $(OBJS)
    $(CC) $(CFLAGS) $(OBJS) -o $@

server.o: rio.h
rio.o: rio.h

clean:
    rm -f *~ *.o $(PROG) core a.out

如果您需要其他库,那么您可以使用:

CC = gcc
CFLAGS = -Wall -Werror -Wmissing-prototypes
OBJS = server.o rio.o
PROG = sysstatd
LOCALLIBDIR = /usr/local/lib
LDFLAGS = -L$(LOCALLIBDIR)
LDLIBS  = -lone -ltwo

all: $(PROG)

$(PROG): $(OBJS)
    $(CC) $(CFLAGS) $(OBJS) -o $@ $(LDFLAGS) $(LDLIBS)

server.o: rio.h
rio.o: rio.h

clean:
    rm -f *~ *.o $(PROG) core a.out

【讨论】:

  • 看到它像这样逐步改进,非常有益。谢谢。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-01-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多