Как интегрировать gnatmake / gnatbind / gnatlink в файлы CMake для кода C / Ada? - PullRequest
4 голосов
/ 23 апреля 2020

Я написал код на нескольких языках (C, C ++, Fortran77, Fortran90), и я могу скомпилировать его без каких-либо проблем с помощью CMake. Это прекрасно работает.

Теперь я хотел бы добавить в main (), которая написана в C, некоторую функцию Ada, и я хочу скомпилировать ее с помощью CMake. Учитывая, что я не могу связать свою функцию Ada с основной с помощью CMake, я получаю

main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal

Я сделал еще один упрощенный тест с использованием основной функции (написанной в C), вызывая только Функция Ада, которую я кодировал, и я скомпилировал ее с помощью

gcc -c main.c
gnatmake -c lib_ada.ali
gnatbind -n lib_ada.ali
gnatlink lib_ada.ali main.o -o exe

, и она работает. Знаете ли вы, как я могу интегрировать этот подход в CMakeList.txt?

Примечание: я думаю (возможно, я ошибаюсь), я не могу использовать единственный gnatlink, потому что мне нужно связать все другие функции, которые у меня уже есть.

Здесь приведен минимальный воспроизводимый пример.

--- main. c ---

#include <stdio.h>

extern int adainit();
extern int adafinal();
extern int Add(int,int);

int main()
{
    adainit();
    printf ("Sum of 3 and 4 is: %d\n", Add (3,4));
    adafinal();

    return 0;
}

--- lib_test.adb ---

package body Lib_Test is
    function Ada_Add (A, B : Integer) return Integer is
    begin
        return A + B;
    end Ada_Add;
end Lib_Test;

--- lib_test.ads ---

package Lib_Test is
   function Ada_Add (A, B : Integer) return Integer;
   pragma Export (C, Ada_Add, "Add");
end Lib_Test;

1 ° test: если вы компилируете с помощью следующих команд:

gcc -c main.c
gnatmake -c lib_test.adb
gnatbind -n lib_test.ali
gnatlink lib_test.ali main.o -o exe

и запускаете ./exe Вы получаете Sum of 3 and 4 is: 7.

2 ° тест: я пытался использовать следующий файл CMake (CMakeLists.txt), связывающий * .a

cmake_minimum_required(VERSION 2.6)
project(Ada2C)

enable_language(C)

set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
set(CMAKE_VERBOSE_MAKEFILE ON)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -m64")

find_library(TEST_lib lib_test.a PATHS ${CMAKE_CURRENT_SOURCE_DIR})
message(STATUS "Finding library: ${TEST_lib}")
add_executable(TEST_release ${CMAKE_CURRENT_SOURCE_DIR}/main.c)
target_link_libraries(TEST_release ${TEST_lib})

Я генерирую библиотеку lib_test.a для функции Ада

gnatmake lib_test.adb
ar rc lib_test.a

я запускаю cmake и make и получаю

main.c:(.text.startup+0x16a): undefined reference to adainit
main.c:(.text.startup+0x179): undefined reference to adafunction
main.c:(.text.startup+0x190): undefined reference to adafinal

1 Ответ

4 голосов
/ 24 апреля 2020

Больше комментария, чем ответа, но слишком длинно для комментария, поэтому здесь идет речь:

Компиляция кода Ada в ваш двоичный файл означает, что вашему двоичному файлу необходим доступ к среде выполнения GNAT. Это единственное, что gnatlink делает, когда вы используете его для ссылки на конечный исполняемый файл. Другое дело, что b~<something>.ad{s,b} source gnatbind генерирует то, что вам нужно скомпилировать и связать, как уже упоминалось другими.

Самый чистый способ встроить Аду в C, который я видел до сих пор, это создать инкапсулированная библиотека. Это, вероятно, не имеет смысла, если ваша настоящая проблема только с одной функцией Ады, но это имеет место с большими кусками Ады. Инкапсулированная библиотека будет общей библиотекой, в которую встроена среда выполнения GNAT. Совместная библиотека позволяет ей неявно обрабатывать инициализацию во время загрузки библиотеки, поэтому вам больше не нужно adainit() / adafinal().

Самый простой способ создать инкапсулированную библиотеку - использовать файл ada_code.gpr:

project ada_code is
   for Library_Name use "mylib";
   for Library_Dir use "lib";
   for Library_Kind use "relocatable";
   for Library_Standalone use "encapsulated";
   for Library_Auto_Init use "true";
   for Library_Interface use ("All", "Packages", "In.Your", "Ada.Code");
   for Source_Dirs use ("adasrc");
end ada_code;

В CMake вы можете сделать:

# tell CMake how to call `gprbuild` on the `.gpr` file.
# you may need to replace `gprbuild` with the absolute path to it
# or write code that finds it on your system.
add_custom_target(compile_mylib
        COMMAND gprbuild -P ada_code.gpr)

# copy the library file generated by gprbuild to CMake's build tree
# (you may skip this and just link against the file in the source tree)
add_custom_command(
        OUTPUT ${CMAKE_CURRENT_BINARY_DIR}/mylib.so
        DEPENDS compile_mylib
        COMMAND ${CMAKE_COMMAND} -E copy
                ${CMAKE_SOURCE_DIR}/lib/mylib.so
                ${CMAKE_CURRENT_BINARY_DIR}/mylib.so)

# ... snip ...

# link to the copied library
# I am not 100% sure this adds the correct dependency to the custom command.
# You may need to experiment a bit yourself
target_link_libraries(TEST_release ${CMAKE_CURRENT_BINARY_DIR}/mylib.so)

В своем файле C вы Затем можно удалить все, что связано с adainit() и adafinal().

...