我今天遇到了Makefile的问题。这是相关的代码:
我有以下目录结构:
/bin
/obj
/headers
config.h
test-config.h
/lib
/src
/test
/src
/bin
/obj
Makefile
Makefile
根目录是我的应用程序代码所在的位置,测试目录是我编写测试代码的地方。主Makefile是很正常的,并按预期编译所有内容。测试目录mv
中的Makefile是config.h
文件的.bak
文件,然后将test-config.h
移动为新的config.h
,然后编译主代码,将根obj /中的所有内容移动到test的obj文件夹中。然后继续编译测试。
我的问题是主配置文件中的常量仍然出现在我的代码中。所以我假设配置文件出错并编译根级代码。这是我的测试Makefile:
#Configurations and setup
CC = cc
CFLAGS = -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I../headers -Isrc
LINKFLAGS = $(CFLAGS)
LIBS = ../lib/wolkykim-qdecoder-63888fc/src/libqdecoder.a
OBJECTS := $(patsubst src/%.c,obj/%.o,$(wildcard src/*.c))
TARGETS := $(patsubst src/%.c,bin/%.out,$(wildcard src/*.c))
#internals are non cgi scripts that we need
INTERNAL := $(patsubst src/internal/%.c,obj/%.o,$(wildcard ../src/internal/*.c))
#Commands to help test and run programs:
valgrind = valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes
.PHONY: clean
all: ${TARGETS}
$(TARGETS): copyobjects $(OBJECTS)
${CC} ${LINKFLAGS} -g -o $@ $(patsubst bin/%.out, obj/%.o, $@ ) $(INTERNAL) ${LIBS}
clean:
rm -f obj/*.o ${TARGETS}
rm -f ../obj/*.o
copyobjects:
-mv ../headers/config.h ../headers/config.h.bak
-mv ../headers/test-config.h ../headers/config.h
rm -f obj/*.o
cd ../ && make && cd test
cp ../obj/*.o obj/
-mv ../headers/config.h ../headers/test-config.h
-mv ../headers/config.h.bak ../headers/config.h
$(OBJECTS): obj/%.o : src/%.c
${CC} ${CFLAGS} -c -o $@ $<
test: $(TARGETS)
-@rm /tmp/data-test || true #remove any test data created so far
$(valgrind) ./$<
麻烦的定义是:
//config.h
#ifndef DATA_DIR
#define DATA_DIR "/path/to/program/data/"
#endif
//test-config.h
#undef DATA_DIR
#ifndef DATA_DIR
#define DATA_DIR "/tmp/data-test/"
#endif
您可以在此处找到整个项目的检查源代码:https://github.com/EJEHardenberg/pChat
我很困惑为什么它不能正常工作并且在与Makefile协调运行预处理器时尝试使用Google搜索,但我找不到任何看似相关的东西。
我的测试程序如下:
//test-init.c
#include "testp.h"
int main(){
pci_init();
/* There should now be a DATA_DIR directory and a users index */
assert( directory_exists(DATA_DIR) == 1 );
assert( file_exists(DATA_DIR USERS_INDEX) == 1 );
}
//testp.h
#ifndef __TEST_H__
#define __TEST_H__
/* Set the Data Directory to the test Directory */
#undef DATA_DIR
#define DATA_DIR "/tmp/data-test/"
#include "base.h"
#include <assert.h>
#endif
断言失败: test-init.out:src / test-init.c:7:main:断言`directory_exists(“/ tmp / data-test /”)== 1'失败。
目录存在的是一个测试显而易见的函数并返回0或1
user@Turing ~/Programming/C/pChat/test $ make test
mv ../headers/config.h ../headers/config.h.bak
mv ../headers/test-config.h ../headers/config.h
rm -f obj/*.o
cd ../ && make clean all && cd test
make[1]: Entering directory `/home/user/Programming/C/pChat'
rm -f obj/*.o bin/heartbeat.cgi
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I./headers -c -o obj/heartbeat.o src/heartbeat.c
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I./headers -c src/internal/data-manip.c -o obj/data-manip.o
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I./headers -c src/internal/fasthash.c -o obj/fasthash.o
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I./headers -o bin/heartbeat.cgi obj/heartbeat.o obj/data-manip.o obj/fasthash.o lib/wolkykim-qdecoder-63888fc/src/libqdecoder.a
make[1]: Leaving directory `/home/user/Programming/C/pChat'
cp ../obj/*.o obj/
mv ../headers/config.h ../headers/test-config.h
mv ../headers/config.h.bak ../headers/config.h
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I../headers -Isrc -c -o obj/test-init.o src/test-init.c
cc -std=gnu99 -pedantic -Wall -Wextra -Werror -g -I../headers -Isrc -g -o bin/test-init.out obj/test-init.o ../src/internal/data-manip.c ../src/internal/fasthash.c ../lib/wolkykim-qdecoder-63888fc/src/libqdecoder.a
rm: cannot remove `/tmp/data-test': No such file or directory
valgrind --tool=memcheck --leak-check=yes --show-reachable=yes --num-callers=20 --track-fds=yes ./bin/test-init.out
==4083== Memcheck, a memory error detector
==4083== Copyright (C) 2002-2011, and GNU GPL'd, by Julian Seward et al.
==4083== Using Valgrind-3.7.0 and LibVEX; rerun with -h for copyright info
==4083== Command: ./bin/test-init.out
==4083==
Could not run init for Private Chat. Could not create directory: /home/user/Programming/pChat/data/
test-init.out: src/test-init.c:7: main: Assertion `directory_exists("/tmp/data-test/") == 1' failed.
==4083==
==4083== FILE DESCRIPTORS: 3 open at exit.
==4083== Open file descriptor 2: /dev/pts/0
==4083== <inherited from parent>
==4083==
==4083== Open file descriptor 1: /dev/pts/0
==4083== <inherited from parent>
==4083==
==4083== Open file descriptor 0: /dev/pts/0
==4083== <inherited from parent>
==4083==
==4083==
==4083== HEAP SUMMARY:
==4083== in use at exit: 0 bytes in 0 blocks
==4083== total heap usage: 3 allocs, 3 frees, 502 bytes allocated
==4083==
==4083== All heap blocks were freed -- no leaks are possible
==4083==
==4083== For counts of detected and suppressed errors, rerun with: -v
==4083== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 2 from 2)
make: *** [test] Aborted (core dumped)
答案 0 :(得分:0)
所以我修好了。这是如何:
在我的Makefile的copyobjects目标中,我有以下内容:
copyobjects:
-mv ../headers/config.h ../headers/config.h.bak
-mv ../headers/test-config.h ../headers/config.h
rm -f obj/*.o
cd ../ && make && cd test
cp ../obj/*.o obj/
-mv ../headers/config.h ../headers/test-config.h
-mv ../headers/config.h.bak ../headers/config.h
test: $(TARGETS)
-@rm /tmp/data-test || true #remove any test data created so far
$(valgrind) ./$<
我按照预期移动了配置文件。这就是现在的工作:
copyobjects:
-mv ../headers/config.h ../headers/config.h.bak
-mv ../headers/test-config.h ../headers/config.h
rm -f obj/*.o
cd ../ && make && cd test
cp ../obj/*.o obj/
test: $(TARGETS)
-@rm /tmp/data-test || true #remove any test data created so far
$(valgrind) ./$<
-@mv ../headers/config.h ../headers/test-config.h
-@mv ../headers/config.h.bak ../headers/config.h
问题似乎是定义在链接时间之前没有“编织”到实际的二进制文件中,所以如果我编译成带有标题X或标题Y的目标文件并不重要,它只在我链接时才重要反对。
简而言之:#define
实际上是在cc
编译的链接阶段被替换而不是编译阶段(我原先想到的)我查看了man cc
对于这样说的东西,但该手册页非常长。我发现有相互矛盾的证据here说preprocesser在链接之前在源上运行。但是:at this link
(我更信任它)它说
无论您是通过gcc还是cpp使用预处理器,都会首先运行编译器驱动程序。该程序的目的是将您的命令转换为执行实际工作的程序的调用。他们的命令行界面与文档界面相似但不完全相同,如有更改,恕不另行通知。
因此,首先运行编译器(获取我的.o文件)然后运行定义。如果不是这种情况,请在下面给出适当的参考意见。
如下所述,预处理器在编译器和链接器之前运行。真正的问题是我的Makefile配置和依赖的顺序。