Нужна помощь с досадными ошибками в Makefile - g++: g++ и ошибки оболочки - и советы по разработке Multi-Makefile
У меня есть make-файл:
#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
Это вызывает второй make-файл после того, как он создает и заполняет структуру каталогов.
Второй make-файл выглядит следующим образом:
#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
..AGAIN сборка завершается успешно, правильно создавая исполняемый файл
Вторая ошибка, которую я получаю, возникает, когда ничего не поделаешь... когда это происходит, я получаю:
/bin/sh: -c: line 0: unexpected EOF while looking for matching ``'
/bin/sh: -c: line 1: syntax error: unexpected end of file
Пожалуйста, будьте осторожны... Я прочитал базовые учебники по make-файлам, включая учебник по gnu makefile, но, похоже, существует скачок между созданием небольшой программы с несколькими локальными источниками и большой программой с необходимостью для вложенных каталогов, данных файлы и т. д. Я пытаюсь совершить этот скачок... к сожалению, у меня нет лучших практических сборочных файлов из прошлого кода, поскольку я работаю в небольшой исследовательской группе в университете, а не в корпоративной атмосфере.
Мой основной подход заключается в создании базового каталога со следующими
[dir] source/
[dir] data/
[dir] makefiles/
[dir] build/ **gets created
Makefile
Makefile верхнего уровня создает подкаталог в каталоге сборки, копирует необходимые источники (скажем, для конкретной тестовой программы и необходимые файлы данных, а также make-файл для создания всех источников. Makefile верхнего уровня затем вызывает make-файл уровня сборки.
Я был бы открыт для идей о том, как упростить этот процесс, но был бы признателен, если бы мы ПЕРВЫЕ исправили ошибки.
Заранее спасибо!!!
PS Я работаю на Centos 5.4, GNU Make 3.81, gcc версии 4.1.2 20080704 (Red Hat 4.1.2-44) .... GNU Make и gcc являются 64-битными версиями...
2 ответа
Это исправление, похоже, устраняет обе ваши ошибки:
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 ...)
Команда для вызова оболочки вне правила. Здесь нет необходимости использовать его, так как это команда в правиле - это уже происходит в подоболочке. Также обратите внимание, что это использует $(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
Что касается рационализации, вы можете многое сделать. Вы можете уменьшить длину вашего второго make-файла примерно вдвое и исправить то, что выглядит как ряд ошибок, а с первым вы можете сделать еще лучше. Это зависит от того, сколько "магии" вы можете терпеть. Вот быстрая попытка оптимизировать ваш второй 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 $@
Для начала вы можете избавиться от всех команд mv и использовать встроенные переменные make, например
$(OBJ_DIR)/parameter_manager.o: $(SOURCE_DIR)/parameter_manager.cpp $(SOURCE_DIR)/common.h
$(CC) $(CFLAGS) -o $@ $<