需要帮助 w/ 恼人的 Makefile 错误 -- g++: g++ 和 shell 错误 -- 和 Multi-Makefile 设计建议

Posted

技术标签:

【中文标题】需要帮助 w/ 恼人的 Makefile 错误 -- g++: g++ 和 shell 错误 -- 和 Multi-Makefile 设计建议【英文标题】:Need Help w/ Annoying Makefile Errors -- g++: g++ and shell errors -- and Multi-Makefile Design Advice 【发布时间】:2010-06-29 22:11:44 【问题描述】:

我有一个生成文件:

#Nice, wonderful makefile written by Jason
CC=g++
CFLAGS=-c -Wall
BASE_DIR:=.
SOURCE_DIR:=$(BASE_DIR)/source
BUILD_DIR:=$(BASE_DIR)/build
TEST_DIR:=$(BASE_DIR)/build/tests
MAKEFILE_DIR:=$(BASE_DIR)/makefiles
DATA_DIR:=$(BASE_DIR)/data
DATA_DIR_TESTS:=$(DATA_DIR)/tests
MOLECULE_UT_SOURCES :=  $(SOURCE_DIR)/molecule_test/main.cc \
    $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/molecule_manager.cpp \
    $(SOURCE_DIR)/molecule_manager_main.h \
    $(SOURCE_DIR)/molecule_manager_main.cpp \
    $(SOURCE_DIR)/molecule_reader.h \
    $(SOURCE_DIR)/molecule_reader.cpp \
    $(SOURCE_DIR)/molecule_reader_psf_pdb.h \
    $(SOURCE_DIR)/molecule_reader_psf_pdb.cpp \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.h \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.cpp \
    $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parameter_manager.cpp \
    $(SOURCE_DIR)/parser.h \
    $(SOURCE_DIR)/parser.cpp \
    $(SOURCE_DIR)/common.h
MOLECULE_UT_DATA := \
    $(DATA_DIR_TESTS)/molecule_test/par_oxalate_and_friends.inp \
    $(DATA_DIR_TESTS)/molecule_test/dicarboxy-octane_4.pdb \
    $(DATA_DIR_TESTS)/molecule_test/dicarboxy-octane_4.psf
PARAM_UT_SOURCES :=  $(SOURCE_DIR)/parameter_test/main.cc \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.h \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.cpp \
    $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parameter_manager.cpp \
    $(SOURCE_DIR)/parser.h \
    $(SOURCE_DIR)/parser.cpp \
    $(SOURCE_DIR)/common.h
PARAM_UT_DATA := $(DATA_DIR_TESTS)/molecule_test/par_oxalate_and_friends.inp

molecule_test : molecule_test_prepare_sources molecule_test_prepare_makefiles \
    molecule_test_prepare_data_files
    @$(shell cd $(TEST_DIR)/molecule_unit_test/; \
    make ./bin/molecule_test)

molecule_test_prepare_sources: molecule_test_dir
    @echo Copying sources...
    @cp --preserve $(MOLECULE_UT_SOURCES) \
    $(TEST_DIR)/molecule_unit_test/source

molecule_test_prepare_makefiles: $(MAKEFILE_DIR)/Makefile.molecule_test
    @cp  --preserve $(MAKEFILE_DIR)/Makefile.molecule_test \
    $(TEST_DIR)/molecule_unit_test/Makefile

molecule_test_prepare_data_files:
    cp --preserve $(MOLECULE_UT_DATA) $(TEST_DIR)/molecule_unit_test/bin/

molecule_test_dir:
    @if test -d $(BUILD_DIR); then \
        echo Build exists...; \
        else \
        echo Build directory does not exist, making build dir...; \
    mkdir $(BUILD_DIR); \
        fi
    @if test -d $(TEST_DIR); then \
        echo Tests exists...; \
        else \
        echo Tests directory does not exist, making tests dir...; \
    mkdir $(TEST_DIR); \
        fi
    @if test -d $(TEST_DIR)/molecule_unit_test; then \
        echo Molecule unit test directory exists...; \
        else \
        echo Molecule unit test directory does \
        not exist, making build dir...; \
        mkdir $(TEST_DIR)/molecule_unit_test; \
        fi
    @if test -d $(TEST_DIR)/molecule_unit_test/source; then \
        echo Molecule unit test source directory exists...; \
        else \
        echo Molecule unit test source directory does \
        not exist, making build dir...; \
        mkdir $(TEST_DIR)/molecule_unit_test/source; \
        fi
    @if test -d $(TEST_DIR)/molecule_unit_test/obj; then \
        echo Molecule unit test object directory exists...; \
        else \
        echo Molecule unit test object directory does \
        not exist, making object dir...; \
        mkdir $(TEST_DIR)/molecule_unit_test/obj; \
        fi
    @if test -d $(TEST_DIR)/molecule_unit_test/bin; then \
        echo Molecule unit test executable directory exists...; \
        else \
        echo Molecule unit test executable directory does \
        not exist, making executable dir...; \
        mkdir $(TEST_DIR)/molecule_unit_test/bin; \
        fi

param_test : param_test_prepare_sources param_test_prepare_makefiles \
    param_test_prepare_data_files
    @$(shell cd $(TEST_DIR)/param_unit_test/; \
    make ./bin/param_test)

param_test_prepare_sources: param_test_dir
    @echo Copying sources...
    @cp --preserve $(PARAM_UT_SOURCES) $(TEST_DIR)/param_unit_test/source

param_test_prepare_makefiles: $(MAKEFILE_DIR)/Makefile.param_test
    @cp  --preserve $(MAKEFILE_DIR)/Makefile.param_test \
    $(TEST_DIR)/param_unit_test/Makefile

param_test_prepare_data_files:
    cp --preserve $(PARAM_UT_DATA) $(TEST_DIR)/param_unit_test/bin/

param_test_dir:
    @if test -d $(BUILD_DIR); then \
        echo Build exists...; \
        else \
        echo Build directory does not exist, making build dir...; \
    mkdir $(BUILD_DIR); \
        fi
    @if test -d $(TEST_DIR); then \
        echo Tests exists...; \
        else \
        echo Tests directory does not exist, making tests dir...; \
    mkdir $(TEST_DIR); \
        fi
    @if test -d $(TEST_DIR)/param_unit_test; then \
        echo Param unit test directory exists...; \
        else \
        echo Param unit test directory does \
        not exist, making build dir...; \
        mkdir $(TEST_DIR)/param_unit_test; \
        fi
    @if test -d $(TEST_DIR)/param_unit_test/source; then \
        echo Param unit test source directory exists...; \
        else \
        echo Param unit test source directory does \
        not exist, making build dir...; \
        mkdir $(TEST_DIR)/param_unit_test/source; \
        fi
    @if test -d $(TEST_DIR)/param_unit_test/obj; then \
        echo Param unit test object directory exists...; \
        else \
        echo Param unit test object directory does \
        not exist, making object dir...; \
        mkdir $(TEST_DIR)/param_unit_test/obj; \
        fi
    @if test -d $(TEST_DIR)/param_unit_test/bin; then \
        echo Param unit test executable directory exists...; \
        else \
        echo Param unit test executable directory does \
        not exist, making executable dir...; \
        mkdir $(TEST_DIR)/param_unit_test/bin; \
        fi

在创建并填充目录结构后调用第二个 makefile。

第二个makefile如下:

#Nice, wonderful makefile written by Jason
CC=g++
CFLAGS=-c -Wall
SOURCE_DIR:=./source
OBJ_DIR:=./obj
EXE_DIR:=./bin

$(EXE_DIR)/molecule_test : $(OBJ_DIR)/main.o \
    $(OBJ_DIR)/parameter_manager_lj_molecule.o \
    $(OBJ_DIR)/parameter_manager.o $(OBJ_DIR)/parser.o \
    $(OBJ_DIR)/molecule_manager.o $(OBJ_DIR)/molecule_manager_main.o \
    $(OBJ_DIR)/molecule_reader.o \
    $(OBJ_DIR)/molecule_reader_psf_pdb.o
    @$(CC) $(OBJ_DIR)/main.o $(OBJ_DIR)/parameter_manager.o \
    $(OBJ_DIR)/parser.o $(OBJ_DIR)/parameter_manager_lj_molecule.o \
    $(OBJ_DIR)/molecule_manager.o $(OBJ_DIR)/molecule_manager_main.o \
    $(OBJ_DIR)/molecule_reader.o \
    $(OBJ_DIR)/molecule_reader_psf_pdb.o \
    -o molecule_test
    @mv molecule_test $(EXE_DIR)/ 

$(OBJ_DIR)/main.o: $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.h \
    $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/molecule_manager_main.h \
    $(SOURCE_DIR)/molecule_reader.h \
    $(SOURCE_DIR)/molecule_reader_psf_pdb.h \
    $(SOURCE_DIR)/common.h $(SOURCE_DIR)/main.cc
    $(CC) $(CFLAGS) $(SOURCE_DIR)/main.cc
    @mv main.o $(OBJ_DIR)/

$(OBJ_DIR)/molecule_reader.o: $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.h \
    $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/molecule_manager_main.h \
    $(SOURCE_DIR)/molecule_reader.h \
    $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/molecule_reader.cpp
    @mv molecule_reader.o $(OBJ_DIR)/

$(OBJ_DIR)/molecule_reader_psf_pdb.o: $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parameter_manager_lj_molecule.h \
    $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/molecule_manager_main.h \
    $(SOURCE_DIR)/molecule_reader.h \
    $(SOURCE_DIR)/molecule_reader_psf_pdb.h \
    $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/molecule_reader_psf_pdb.cpp
    @mv molecule_reader_psf_pdb.o $(OBJ_DIR)/

$(OBJ_DIR)/molecule_manager.o: $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/molecule_manager.cpp
    @mv molecule_manager.o $(OBJ_DIR)/

$(OBJ_DIR)/molecule_manager_main.o: $(SOURCE_DIR)/molecule_manager.h \
    $(SOURCE_DIR)/molecule_manager_main.h \
    $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/molecule_manager_main.cpp
    @mv molecule_manager_main.o $(OBJ_DIR)/

$(OBJ_DIR)/parameter_manager_lj_molecule.o: $(SOURCE_DIR)/common.h \
    $(SOURCE_DIR)/parameter_manager.h \
    $(SOURCE_DIR)/parser.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/parameter_manager_lj_molecule.cpp
    @mv parameter_manager_lj_molecule.o $(OBJ_DIR)/

$(OBJ_DIR)/parameter_manager.o: $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/parameter_manager.cpp
    @mv parameter_manager.o $(OBJ_DIR)/

$(OBJ_DIR)/parser.o: $(SOURCE_DIR)/parser.h
    @$(CC) $(CFLAGS) $(SOURCE_DIR)/parser.cpp
    @mv parser.o $(OBJ_DIR)/

$(OBJ_DIR)/common.o: $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) $(SOURCE_DIR)/common.h
    mv common.h.gch $(OBJ_DIR)/

我承认我是 Makefiles 的新手。关于如何简化这些文件(没有太多“魔法”)以及如何修复这两个错误,我都想得到建议......

首先我必须说一切正常,可以这么说。当我构建目标时,它会正确创建所有目录并生成可执行文件。当我触摸基础级源目录中的文件时,我的所有文件都会被正确复制并重新编译。所以可以说这些不是“真正的”错误,只是我想摆脱的烦人的错误文本......

第一个错误发生在我运行构建 make molecule_test 时,它需要它执行某些操作。需要做的事都会做,但我也得到:

g++: g++: No such file or directory
g++: g++: No such file or directory
g++: g++: No such file or directory
g++: g++: No such file or directory
g++: g++: No such file or directory
g++: g++: No such file or directory
make: *** [molecule_test] Error 1

..再次构建成功,正确创建可执行文件

我得到的第二个错误发生在无事可做时......当这种情况发生时,我得到:

/bin/sh: -c: line 0: unexpected EOF while looking for matching ``'
/bin/sh: -c: line 1: syntax error: unexpected end of file

请轻点...我已经阅读了基本的 makefile 教程,包括 gnu makefile 教程,但是在使用少量本地资源创建一个小程序和一个需要嵌套的大型程序之间似乎有一个飞跃目录、数据文件等。我正在努力实现这一飞跃......不幸的是,我没有过去代码的最佳实践 makefile,因为我在大学的一个小型研究小组,而不是企业氛围。

我的基本方法是使用以下内容创建一个基本目录

[dir] source/
[dir] data/
[dir] makefiles/
[dir] build/    **gets created
Makefile

顶层 makefile 在 build 目录中创建一个子目录,复制所需的源文件(例如,对于特定的测试程序和所需的数据文件,以及一个 makefile 来制作所有源文件。顶层 makefile 然后调用 build-级别makefile。

我愿意接受有关如何简化此流程的想法,但如果我们首先解决错误,我将不胜感激。

提前致谢!!!

附:我在 Centos 5.4、GNU Make 3.81、gcc 版本 4.1.2 20080704 (Red Hat 4.1.2-44) 上运行 .... GNU Make 和 gcc 都是 64 位版本...

【问题讨论】:

【参考方案1】:

此修复似乎清除了您的两个错误:

molecule_test : molecule_test_prepare_sources molecule_test_prepare_makefiles \
  molecule_test_prepare_data_files
    @cd $(TEST_DIR)/molecule_unit_test && $(MAKE) ./bin/molecule_test

$(shell ...) 命令用于在规则之外调用 shell。这里没有必要使用它,因为这是规则中的命令——它已经在子 shell 中发生了。另请注意,这里使用了$(MAKE) 而不是make(原因有点微妙,只是认为这是一个好习惯)。

你可以更简洁、更安静地做到这一点:

molecule_test : molecule_test_prepare_sources molecule_test_prepare_makefiles \
  molecule_test_prepare_data_files
    @$(MAKE) -s -C $(TEST_DIR)/molecule_unit_test ./bin/molecule_test

至于精简,你可以做很多很多。您可以将第二个 makefile 的长度减少大约一半,并修复一些似乎是错误的错误,并且使用第一个可以做得更好。这取决于你能忍受多少“魔法”。这是简化您的第二个 Makefile 的快速尝试(因为我没有您的文件来测试它,我不能保证它会在没有一些修饰的情况下工作)。

CC=g++
CFLAGS=-c -Wall
SOURCE_DIR:=./source
INCDIRS := -I$(SOURCE_DIR)
OBJ_DIR:=./obj
EXE_DIR:=./bin

VPATH = $(SOURCE_DIR)

$(EXE_DIR)/molecule_test : $(OBJ_DIR)/main.o \
  $(OBJ_DIR)/parameter_manager_lj_molecule.o \
  $(OBJ_DIR)/parameter_manager.o $(OBJ_DIR)/parser.o \
  $(OBJ_DIR)/molecule_manager.o $(OBJ_DIR)/molecule_manager_main.o \
  $(OBJ_DIR)/molecule_reader.o \
  $(OBJ_DIR)/molecule_reader_psf_pdb.o
    @$(CC) $^ -o $@

$(OBJ_DIR)/main.o $(OBJ_DIR)/molecule_reader.o \
  $(OBJ_DIR)/molecule_reader_psf_pdb.o: \
  molecule_manager.h \
  molecule_manager_main.h \
  parameter_manager.h \
  parameter_manager_lj_molecule.h

$(OBJ_DIR)/main.o: main.cpp \
  molecule_reader.h \
  molecule_reader_psf_pdb.h common.h
    $(CC) $(CFLAGS) $(INCDIRS) $< $@

$(OBJ_DIR)/molecule_reader_psf_pdb.o: molecule_reader.h

$(OBJ_DIR)/parameter_manager_lj_molecule.o: parser.h

%.o: %.cpp %.h common.h
    $(CC) $(CFLAGS) $(INCDIRS) $< -o $@

【讨论】:

我认为您需要在最后一行的 $@ 之前添加一个 -o @Paul R:你说得对,谢谢,已修复。它可能有一两个更严重的错误会在测试中出现。 谢谢你们!!现在试试这个。 :) 嗯,我收到错误消息:make[1]: *** No rule to make target main.cpp',obj/main.o'. Stop. 需要...当我尝试制作第二个目标时... 好的,通过将 main.o 目标中的 .cpp 更改为 .cc 来修复我之前的错误...但现在我收到此错误...obj/main.o: file not recognized: File format not recognized ...我读到这是由于如果您的文件扩展名错误...但是我的扩展名现在看起来都很好:O【参考方案2】:

首先,您可以摆脱所有 mv 命令并使用 make 的内置变量,例如

$(OBJ_DIR)/parameter_manager.o: $(SOURCE_DIR)/parameter_manager.cpp $(SOURCE_DIR)/common.h
    $(CC) $(CFLAGS) -o $@ $<

【讨论】:

$@$&lt; 是如何工作的...这些会将对象放在我的对象文件夹中(执行我的最终构建)?我想把它们分开...... @Jason R. Mick:它们是自动变量(参见 gnu make 手册)。 $@ 扩展为目标,$&lt; 扩展为第一个先决条件。 啊。快速提问;我在一个大多数人比我知道的编码要少得多的实验室工作,因此至少可以说维护这个项目可能很难。我担心把这样的好技巧放进去会使情况变得更糟。我不确定我是否应该尝试编写我的代码/makefile 以提高新手的可读性或优化语法,可以这么说。建议??也没有人知道我原来的make系统错误???? @Jason:理想情况下,您希望简化您的 makefile,这可能会使其更加神秘,但希望维护的便利性超过了这一点 - 查看 GNU make 手册中的默认规则,使用% 通配符。您应该能够设置一些默认规则,然后您不那么开明的同事只需更新依赖项,这应该很容易,并且不需要了解 makefile 中更神秘的部分。 谢谢。保罗。但是,对于上述错误仍然没有答案??有人吗?

以上是关于需要帮助 w/ 恼人的 Makefile 错误 -- g++: g++ 和 shell 错误 -- 和 Multi-Makefile 设计建议的主要内容,如果未能解决你的问题,请参考以下文章

C中的Makefile错误

CAShapeLayer 恼人的剪裁错误

停止恼人的IE背景图像闪烁错误

什么是“StringQueryOperatorInput”类型?我怎样才能摆脱这个恼人的 graphql 错误?

MakeFile:不同目录中的标题 - 错误

Makefile 循环依赖被删除