简体   繁体   English

Makefile-通配符和配方构建

[英]Makefile - wildcard and recipe build

I have the following makefile 我有以下makefile

# See gcc/clang manual to understand all flags
CFLAGS += -std=c99 # Define which version of the C standard to use
CFLAGS += -Wall # Enable the 'all' set of warnings
CFLAGS += -Werror # Treat all warnings as error
CFLAGS += -Wshadow # Warn when shadowing variables
CFLAGS += -Wextra # Enable additional warnings
CFLAGS += -O2 -D_FORTIFY_SOURCE=2 # Add canary code, i.e. detect buffer overflows
CFLAGS += -fstack-protector-all # Add canary code to detect stack smashing

# We have no libraries to link against except libc, but we want to keep
# the symbols for debugging
LDFLAGS = -rdynamic

# external libs
# par défaut les chemins classiques

LDFLAGS += -I$(HOME)/local/include
LDFLAGS += -L$(HOME)/local/lib

# Default compiler
CC=gcc

# folders
SOURCE_FOLDER=src
TESTS_FOLDER=tests
PAQUET_FOLDER=paquet
SEND_RECEIVE_DATA_FOLDER=sendAndReceiveData
CLIENT_FOLDER=client
SERVER_FOLDER=server

# folder of sources
PAQUET_FULL_PATH=$(SOURCE_FOLDER)/$(PAQUET_FOLDER)
SEND_RECEIVE_DATA_FULL_PATH=$(SOURCE_FOLDER)/$(SEND_RECEIVE_DATA_FOLDER)
CLIENT_FULL_PATH=$(SOURCE_FOLDER)/$(CLIENT_FOLDER)
SERVER_FULL_PATH=$(SOURCE_FOLDER)/$(SERVER_FOLDER)

# sources files
# On prend tout
PACKET_SOURCES = $(wildcard $(PAQUET_FULL_PATH)/*.c)
SEND_RECEIVE_DATA_SOURCES = $(wildcard $(SEND_RECEIVE_DATA_FULL_PATH)/*.c)
CLIENT_SOURCES = $(wildcard $(CLIENT_FULL_PATH)/*.c)
SERVER_SOURCES = $(wildcard $(SERVER_FULL_PATH)/*.c)

# objects

PACKET_OBJECTS=$(PACKET_SOURCES:.c=.o)
SEND_RECEIVE_DATA_OBJECTS=$(SEND_RECEIVE_DATA_SOURCES:.c=.o)
CLIENT_OBJECTS=$(CLIENT_SOURCES:.c=.o)
SERVER_OBJECTS=$(SERVER_SOURCES:.c=.o)

# another things

# Default target
all: clean server client

client: $(CLIENT_OBJECTS) $(PACKET_OBJECTS); \
        $(CC) $(CFLAGS) $(CLIENT_OBJECTS) $(LDFLAGS);

server: $(SERVER_OBJECTS) $(PACKET_OBJECTS); \
        $(CC) $(CFLAGS) $(SERVER_OBJECTS) $(LDFLAGS);

$(PACKET_OBJECTS): $(PACKET_OBJECTS); \
        $(CC) $(CFLAGS) -lz $(PACKET_OBJECT) $(LDFLAGS);

tests: $(PACKET_OBJECTS) $(TESTS_OBJECTS); \
        $(CC) $(CFLAGS) -lcunit $(LDFLAGS);

.PHONY: clean

clean:
    @rm -f *.o

I got this message : 我收到此消息:

make: Circular src/paquet/packet_implem.o <- src/paquet/packet_implem.o dependency dropped. make:循环src / paquet / packet_implem.o <-src / paquet / packet_implem.o依赖项已删除。 \\ gcc -std=c99 -Wall -Werror -Wshadow -Wextra -O2 -D_FORTIFY_SOURCE=2 -fstack-protector-all -lz -rdynamic -I/home/jy95/local/include -L/home/jy95/local/lib; \\ gcc -std = c99 -Wall -Werror -Wshadow -Wextra -O2 -D_FORTIFY_SOURCE = 2 -fstack-protector-all -lz -rdynamic -I / home / jy95 / local / include -L / home / jy95 / local / lib ; /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o: In function _start': (.text+0x20): undefined reference to main' collect2: error: ld returned 1 exit status Makefile:71: recipe for target 'src/paquet/packet_implem.o' failed make: *** [src/paquet/packet_implem.o] Error 1 /usr/lib/gcc/x86_64-linux-gnu/5/../../../x86_64-linux-gnu/crt1.o:在函数_start': (.text+0x20): undefined reference to main的_start': (.text+0x20): undefined reference to 'collect2:错误:ld返回1退出状态Makefile:71:目标'src / paquet / packet_implem.o'的配方失败:*** [src / paquet / packet_implem.o]错误1

What I want : 我想要的是 :

1) Build the dependancies (PACKET_SOURCES) and (SEND_RECEIVE_DATA_SOURCES) 1)建立依存关系(PACKET_SOURCES)和(SEND_RECEIVE_DATA_SOURCES)
2) Build the client and the server with the dependancies from step 1 2)使用步骤1中的依赖关系构建客户端和服务器
3) The executable "client" will be at the root of the folder. 3)可执行文件“客户端”将位于文件夹的根目录。

How can I correct my errors ? 我该如何纠正错误?

Use -c to generate objects without trying to make an executable, that way you don't need a main 使用-c生成对象而不尝试创建可执行文件,这样您就不需要main

$(PACKET_OBJECTS): $(PACKET_OBJECTS); \
        $(CC) -c $(CFLAGS) -lz $(PACKET_OBJECT) $(LDFLAGS);

I think you might also need a rule like this for your SERVER_OBJECTS 我认为您可能还需要SERVER_OBJECTS这样的规则

.c.o:
        $(CC) -c $(CFLAGS) -lz $< -o $@

The problem occurs in this rule: 此规则中出现问题:

$(PACKET_OBJECTS): $(PACKET_OBJECTS); \
        $(CC) $(CFLAGS) -lz $(PACKET_OBJECT) $(LDFLAGS);

That says that every target in the expansion of $(PACKET_OBJECTS) depends on every target in the expansion of $(PACKET_OBJECTS) . 这表示,在扩大每个目标$(PACKET_OBJECTS)依赖于每一个目标的扩展$(PACKET_OBJECTS) That gives a great many dependency cycles, and in particular it gives you one-element cycles of object files depending on themselves. 这给了很多依赖周期,特别是它给了目标文件一个元素周期,具体取决于它们自己。

In fact, this rule is problematic in several other ways: 实际上,此规则在其他几个方面也存在问题:

  • the recipe does not, in fact, create any of the rule's designated targets 实际上,配方不会创建规则的任何指定目标
  • instead, it attempts to link the object files (see next) together into an executable, assigning the default name to the result (perhaps a.out ). 相反,它尝试将目标文件(请参阅下文) 链接到一个可执行文件中,为结果分配默认名称(也许是a.out )。
  • The recipe references an undefined variable $(PACKET_OBJECT) . 配方引用未定义的变量$(PACKET_OBJECT) I suppose that this is probably a misspelling of $(PACKET_OBJECTS) . 我想这可能是$(PACKET_OBJECTS)的拼写错误。 If instead you mean current target among those given in $(PACKET_OBJECTS) , then that would be spelled $@ . 相反,如果您的意思是$(PACKET_OBJECTS)指定的当前目标,则将其拼写为$@
  • not only do the object files certainly not each have themselves as prerequisites, they also do not have each other as prerequisites. 对象文件不仅不必然彼此具有先决条件,而且彼此之间也不具有先决条件。 The dependencies for each object should be their corresponding sources. 每个对象的依存关系应为其对应的来源。
  • If you indeed mean for this rule to be used to build your object files then the recipe does not need to specify libraries to link in (eg -lz ), and probably should not do so. 如果确实要使用此规则来构建目标文件,则该配方不需要指定要链接的库(例如-lz ),并且可能不应该这样做。

Chances are reasonably good that you could simply delete that rule altogether and thereby be better off. 很有可能,您可以完全删除该规则,从而变得更好。 You might want to add -lz to your LDFLAGS ; 您可能需要将-lz添加到您的LDFLAGS otherwise it would just be lost. 否则,它将丢失。

Additionally, 另外,

  • You probably want to move the -I$(HOME)/local/include option: it does not belong in LDFLAGS, and will not serve its purpose there. 您可能想移动-I$(HOME)/local/include选项:它不属于LDFLAGS,因此在此不起作用。 If you need it, then put it instead in your CPPFLAGS , or maybe in CFLAGS or even INCLUDES . 如果需要,则将其放到CPPFLAGS ,或者放到CFLAGS甚至是INCLUDES

  • Your various rules that build executable targets should provide options that specify the name of the target to build. 构建可执行目标的各种规则应提供指定要构建目标名称的选项。 You can spell that as " -o $@ ", 您可以将其拼写为“ -o $@ ”,

  • It is unconventional to include your clean target as a prerequisite of all . clean目标作为all的前提是不寻常的。 It will always rebuild everything from scratch if you run make without specifying a target. 如果运行make而不指定目标,它将始终从头开始重建所有内容。 Most people prefer to do that only on demand. 大多数人只喜欢按需这样做。

  • Your all target does not build a target named "all", so it, too, should be declared .PHONY . 您的all目标不会构建名为“ all”的目标,因此也应将其声明为.PHONY

Very likely there's more, but I'll leave that for you to sort out. 很可能还有更多,但我会留给您整理。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM