Проблема привязки Ada Makefile

Я работаю над проектом в Ada и хотел бы создать собственный make-файл (поскольку я намерен в конечном итоге взаимодействовать с c и python и хорошо знаком с синтаксисом make-файла и совсем не знаком с синтаксисом проекта gnatmake). Я возился с пользовательской компиляцией и думал, что она работает, но мой make-файл, который, по крайней мере, выглядит так, как будто он выполняет то же самое выполнение из командной строки, сталкивается с проблемами на этапе связывания.

Я полагаю, что у меня, вероятно, ошибка каталога не по одному, или я что-то усложняю/усложняю.

В любом случае, мой проект в настоящее время содержит 3 исходных каталога (но их будет больше). Model содержит «логику», util содержит общие утилиты, а test содержит неупакованные «основные» процедуры. В конце концов у меня также будут некоторые «основные» процедуры в моем каталоге 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)
      \- ...

Я попробовал «базовый» make-файл, который был очень близок к тому, что я хотел:

.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~* в рабочем каталоге всякий раз, когда передается флаг отладки. Поскольку я намереваюсь иметь много исполняемых файлов, это значительно загрязнит мой рабочий каталог.

Таким образом, я шаг за шагом открывал make-файл и в итоге получил:

.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, когда доходит до стадии связывания.

Любой совет?


person LambdaBeta    schedule 04.10.2016    source источник
comment
Делая это таким образом, вы никогда не получите правильных зависимостей. Раньше gnatmake поддерживал -M для вывода зависимостей в форме Makefile, но не более того.   -  person Simon Wright    schedule 04.10.2016


Ответы (2)


Я бы посоветовал вам пересмотреть свое решение решить проблему полностью без файлов проекта. Обычно я использую комбинацию файлов проекта и make-файла для создания проектов Ada с помощью GNAT.

Вам потребуется файл проекта GNAT для каждого каталога объектов, поскольку файл проекта может указывать только на один каталог объектов.

Если у вас есть общие флаги компилятора для большей части проекта, имеет смысл разместить их в общем файле проекта, из которого получаются другие файлы проекта.

person Jacob Sparre Andersen    schedule 04.10.2016
comment
Хорошо, я подумал, что это может быть проблема, выходящая за рамки того, что может сделать make. Пришло время изучить, как использовать файлы проекта GNAT! Спасибо за дозу реальности. - person LambdaBeta; 04.10.2016

Примечание. Использование проектов GNAT является идеальным решением. Тем не менее:

Я нашел проекты GNAT как систему очень громоздкой, тем более что gprbuild еще не является стандартным пакетом для моей системы, а gnatmake устарел с флагом -P. Таким образом, я создал промежуточное решение.

Я создал новый каталог build рядом с моим каталогом src. Внутри 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)/* 

Затем я создал этот очень минимальный Makefile в src:

.SILENT:
BUILD_DIR=../build

% : force_make
    cd $(BUILD_DIR); make $@

force_make:
    true

Теперь я могу запустить make test из моего исходного каталога, и он создаст мой тестовый исполняемый файл, как и ожидалось.

Преимущество этой системы заключается в том, что по мере того, как я узнаю о файлах проекта, я могу легко добавить их в каталог сборки, чтобы обеспечить постепенный переход от чистого решения GNU make к чистому решению проекта GNAT.

person LambdaBeta    schedule 04.10.2016