我正在研究Ada中的一个项目,并且想要一个自定义的makefile(因为我打算最终与c和python接口,并且我非常熟悉makefile语法,并且根本不熟悉gnatmake项目语法)。我搞乱了自定义编译,并认为我有它工作,但我的makefile至少看起来像完全相同的命令行执行在绑定阶段遇到问题。
我想我可能有一个一个一个目录错误,或者过度/不完全复杂的东西。
无论如何,我的项目目前包含3个源目录(但会有更多目录)。模型包含'逻辑',util包含常用实用程序,test包含未打包的' main'程序。最终我还会有一些主要的'我的src目录中的程序。 ASCII图片:
project
\- bin
\- test
\- ....out
\- other_dirs_coming_soon
\- ....out
\- ....out
\- obj
\- all the mess that ada compilation makes
\- including .o, .ali, and b~whatever.ad(b/s)
\- src
\- model
\- ....ad(b/s)
\- util
\- ....ad(b/s)
\- ...
我试过一个基本的' makefile非常接近我的想法:
.PHONY: clean test
MAKE=gnatmake
INCLUDE_DIRS=-Imodel -Iutil -Itest
GNATMAKEFLAGS=-g -fprofile-arcs -ftest-coverage --GNATLINK="gnatlink -v" --GNATBIND="gnatbind -v"
GCCFLAGS=-g -fprofile-arcs -ftest-coverage
OBJDIR=../obj
BINDFLAGS=-a0$(OBJDIR)
PLAYER_TEST_EXE=../bin/player_test.out
test : $(PLAYER_TEST_EXE)
$(PLAYER_TEST_EXE) : test/player_test.adb
gnatmake $< -D $(OBJDIR) $(INCLUDE_DIRS) -o $@ $(GNATMAKEFLAGS)
clean :
@rm -rf $(OBJDIR)/* $(PLAYER_TEST_EXE) b~*
问题是,只要传递调试标志,就会在工作目录中创建那些b~*
个文件。由于我打算有许多可执行文件,这将严重污染我的工作目录。
因此,我逐步打开makefile,最后得到:
.PHONY: clean test
GCC=gcc
BINDER=gnatbind
ADALIBLOC=`gnatls -v | grep adalib`
FLAGS=
LINKFLAGS=-gnatA -gnatWb -gnatiw -gnatws
test: FLAGS+=-g -fprofile-arcs -ftest-coverage
test: LINKFLAGS+=-g
# Where to put the object files and ali extensions
OBJDIR=../obj
# Source directories
MODEL_DIR=model
UTIL_DIR=util
TEST_DIR=test
SRC_DIRS=$(MODEL_DIR) $(UTIL_DIR) $(TEST_DIR)
INC_DIRS=${SRC_DIRS:%=-I%}
LIB_DIRS=${SRC_DIRS:%=-L%}
BIND_DIRS=${SRC_DIRS:%=-aO./%}
# Model sources
MODEL_SPECS=$(wildcard $(MODEL_DIR)/*.ads)
MODEL_BODIES=$(wildcard $(MODEL_DIR)/*.adb)
MODEL_OBJECTS=$(patsubst %.ads,$(OBJDIR)/%.o,$(MODEL_SPECS))
MODEL_ALI=$(patsubst %.ads,$(OBJDIR)/%.ali,$(MODEL_SPECS))
# Util sources
UTIL_SPECS=$(wildcard $(UTIL_DIR)/*.ads)
UTIL_BODIES=$(wildcard $(UTIL_DIR)/*.adb)
UTIL_OBJECTS=$(patsubst %.ads,$(OBJDIR)/%.o,$(UTIL_SPECS))
UTIL_ALI=$(patsubst %.ads,$(OBJDIR)/%.ali,$(UTIL_SPECS))
# All sources
ALL_SPECS=$(MODEL_SPECS) $(UTIL_SPECS)
ALL_BODIES=$(MODEL_BODIES) $(UTIL_BODIES)
ALL_OBJECTS=$(MODEL_OBJECTS) $(UTIL_OBJECTS)
ALL_ALIS=$(MODEL_ALI) $(UTIL_ALI)
# Executables
EXE_DIR=../bin
PLAYER_TEST_EXE=$(EXE_DIR)/test/player_test.out
# Targets
test : $(PLAYER_TEST_EXE)
# Executable creation
$(EXE_DIR)/%.out : $(EXE_DIR)/%.o $(ALL_OBJECTS)
cd $(EXE_DIR)
$(GCC) $*.o $(ALL_OBJECTS) $(FLAGS) -o $@ $(LIB_DIRS) -L$(ADALIBLOC)/libgnat.a --static-libgcc
# Executable object creation
$(EXE_DIR)/%.o : $(EXE_DIR)/%.adb
cd $(OBJBINDIR)
$(GCC) -c $(FLAGS) $(LINKFLAGS) $< -o $@
# Executable source creation
$(EXE_DIR)/%.adb : $(OBJDIR)/%.ali $(ALL_OBJECTS)
cd $(EXE_DIR)
$(BINDER) $(BIND_DIRS) $(INC_DIRS) -v -x ../$< -o ../$*.adb
# Object creation
$(OBJDIR)/%.o : %.adb %.ads
$(OBJDIR)/%.o :
if [ -a $*.adb ]; then \
gcc -c $*.adb $(INC_DIRS) -o $@ $(FLAGS); \
else \
gcc -c $*.ads $(INC_DIRS) -o $@ $(FLAGS); \
fi;
# ALI creation
$(OBJDIR)/%.ali : %.adb %.ads
$(OBJDIR)/%.ali :
if [ -a $*.adb ]; then \
gcc -c $*.adb $(INC_DIRS) -o $(OBJDIR)/$*.o $(FLAGS); \
else \
gcc -c $*.ads $(INC_DIRS) -o $(OBJDIR)/$*.o $(FLAGS); \
fi;
clean:
@rm -f $(ALL_OBJECTS) $(ALL_ALI)
这似乎非常接近,除非它到达绑定阶段时找不到player_test.ali。
有什么建议吗?
答案 0 :(得分:5)
我建议您重新考虑您在没有项目文件的情况下完全解决问题的决定。我通常使用项目文件和makefile的组合来构建具有GNAT的Ada项目。
每个对象目录需要一个GNAT项目文件,因为项目文件只能指向一个对象目录。
如果你有大多数项目的通用编译器标志,那么将它们放在一个公共项目文件中是有意义的,其他项目文件来自这个文件。
答案 1 :(得分:1)
注意:使用GNAT项目是理想的解决方案。尽管如此:
我发现GNAT项目作为一个系统非常麻烦,特别是因为gprbuild还不是我的系统的标准包,并且gnatmake已经删除了-P
标志。因此,我创建了一个中间解决方案。
我在build
目录旁边创建了一个新目录src
。在build
里面,我对所有源目录进行了符号链接。然后我在build中添加了这个Makefile:
.PHONY: clean test
.SILENT:
FLAGS=-d
GNATLINKFLAGS=
GNATBINDFLAGS=
test: FLAGS+=-g -fprofile-arcs -ftest-coverage
MAKE=gnatmake
INCLUDE_DIRS=-Imodel -Iutil -Itest
GNATLINK=--GNATLINK="gnatlink $(GNATLINKFLAGS)"
GNATBIND=--GNATBIND="gnatbind $(GNATBINDFLAGS)"
GNATMAKEFLAGS=$(FLAGS) $(GNATLINK) $(GNATBIND)
OBJDIR=../obj
SRCDIR=../src
# Executable definitions
PLAYER_TEST_SRC=test/player_test.adb
PLAYER_TEST_EXE=../bin/player_test.out
test : $(PLAYER_TEST_EXE)
$(PLAYER_TEST_EXE) : force_make
gnatmake $(PLAYER_TEST_SRC) -D $(OBJDIR) $(INCLUDE_DIRS) -o $@ $(GNATMAKEFLAGS)
force_make:
true
clean :
@rm -rf $(OBJDIR)/*
然后我在src中创建了这个非常小的Makefile:
.SILENT:
BUILD_DIR=../build
% : force_make
cd $(BUILD_DIR); make $@
force_make:
true
现在我可以从源目录中运行make test
,它将按预期创建我的测试可执行文件。
这个系统的好处是,当我了解项目文件时,我可以轻松地将它们添加到构建目录中,以便允许从纯GNU make解决方案到纯GNAT项目解决方案的增量转换。