【问题标题】:Ada Makefile Binding IssueAda Makefile 绑定问题
【发布时间】:2016-10-04 16:21:32
【问题描述】:

我正在 Ada 开发一个项目,想要一个自定义 makefile(因为我打算最终与 c 和 python 交互,并且非常熟悉 makefile 语法,但完全不熟悉 gnatmake 项目语法)。我搞砸了自定义编译,并认为它可以工作,但我的 makefile 至少看起来像执行完全相同的命令行执行,但在绑定阶段遇到了问题。

我想我可能遇到了一个单独的目录错误,或者是过度/不足使某些事情变得复杂。

无论如何,我的项目目前包含 3 个源目录(但还会有更多)。模型包含“逻辑”,实用程序包含常用实用程序,测试包含未打包的“主要”程序。最终,我的 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。

有什么建议吗?

【问题讨论】:

  • 这样做,您将永远无法获得正确的依赖关系。 gnatmake 曾经支持 -M 以 Makefile 形式输出依赖关系,但不再支持。

标签: makefile ada gnat


【解决方案1】:

我建议您重新考虑在没有项目文件的情况下完全解决问题的决定。我通常结合使用项目文件和 makefile 来使用 GNAT 构建 Ada 项目。

每个对象目录都需要一个 GNAT 项目文件,因为项目文件只能指向单个对象目录。

如果大多数项目都有通用的编译器标志,那么将它们放在一个通用的项目文件中是有意义的,其他项目文件都是从该文件派生的。

【讨论】:

  • 好的,我认为这可能是 make 可以做的范围之外的问题。是时候研究如何使用 GNAT 项目文件了!谢谢你的真实剂量。
【解决方案2】:

注意:使用 GNAT 项目是理想的解决方案。尽管如此:

我发现 GNAT 项目作为一个系统非常麻烦,特别是因为 gprbuild 还不是我系统的标准包,并且 gnatmake 已经弃用了-P 标志。因此,我创建了一个中间解决方案。

我在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 项目解决方案。

【讨论】:

    猜你喜欢
    • 2011-09-30
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多