我正在开发一个包含两个程序,一个服务器和一个客户端的C项目 我的项目结构:
.
+--/bin
| +--/client
| +--/server
|
+--/lib
| +--header1.h
| +--header2.h
| +--header3.h
|
+--/obj
| +--/client
| +--/server
|
+--/src
| +--/client
| | +--files.c
| +--/server
| +--otherfiles.c
|
+--Makefile
现在我被困在Makefile上,我的程序都需要不同的和一些重叠的标题。我试着查看其他项目/存储库,但这对我没有帮助 这就是我目前得到的:
SOURCES_CLIENT = ${wildcard src/client/files.c}
SOURCES_SERVER = ${wildcard src/client/otherfiles.c}
HEADERS_CLIENT = ${wildcard lib/header1.h lib/header2.h}
HEADERS_SERVER = ${wildcard lib/header2.h lib/header3.h}
OBJ_CLIENT = ${SOURCES_CLIENT:.c=.o}
OBJ_SERVER = ${SOURCES_SERVER:.c=.o}
CC = gcc
CFLAGS = #not relevant
all: client server
client: ${OBJ_CLIENT}
${CC} -o $@ $^
server: ${OBJ_SERVER}
${CC} -o $@ $^
如何使用相应的头文件创建通配符规则以将源文件转换为目标文件(在正确的bin /目录中)?我的Makefile似乎也是可以优化的,如果是这样的话?
答案 0 :(得分:0)
这两条规则应该在
之后完成obj/client/%.o: src/client/%.c $(HEADERS_CLIENT)
$(CC) -c -o $@ $<
obj/server/%.o: src/server/%.c $(HEADERS_SERVER)
$(CC) -c -o $@ $<
答案 1 :(得分:0)
我认为你的基本变量定义实际上看起来应该更像这样:
SOURCES_CLIENT = ${wildcard src/client/*.c}
SOURCES_SERVER = ${wildcard src/server/*.c}
HEADERS_CLIENT = ${wildcard lib/client*.h}
HEADERS_SERVER = ${wildcard lib/server*.h}
您需要了解的关于make
的第一件事是它只知道关于构建工具,目录或文件的 nothing 。它只是操作字符串,并选择它使用的字符串的子集和表单作为shell命令发出,时间和顺序由表达的规则集控制。
其中的含义是,如果要构建给定目标,则必须为完全该目标编写规则。特别是,当您从项目的根目录运行make
时,所需的二进制文件(在您的方案中)是 不是 client
和{ {1}},它们是server
和bin/client
。同样,与bin/server
对应的所需对象文件不是src/client/files.c
或files.o
,而是src/client/files.o
。
理解了这一点,下一个业务顺序是正确定义目标文件列表。您似乎已经非常致力于GNU make,这使得事情变得更容易(在可移植性方面需要付出一些代价)。而不是obj/client/files.o
和OBJ_CLIENT
的当前定义,它们提供的对象文件位于不同于您需要的位置,使用像这样的(GNU特定的)替换引用的东西可以起作用:
OBJ_SERVER
但是,完成此操作后,您需要编写用于构建目标文件的显式规则; OBJ_CLIENT = $(SOURCES_CLIENT:src/client/%.c=obj/client/%.o)
OBJ_SERVER = $(SOURCES_SERVER:src/server/%.c=obj/server/%.o)
的默认规则不处理所需的跨目录通信。您可以有效地使用GNU模式规则。这也是您在头文件中引入依赖项的地方:
make
再次考虑到您必须提供构建规则以命名您实际想要构建的目标的事实,您可以将它们全部放在一起:
obj/client/%.o: src/client/%.c $(HEADERS_CLIENT)
$(CC) $(CPPFLAGS) $(CFLAGS) -c $< -o $@