如何将 gnatmake/gnatbind/gnatlink 集成到 C/Ada 代码的 CMake 文件中?

Mat*_*teo 5 c ada cmake gnat

我用几种语言(C、C++、Fortran77、Fortran90)编写了代码,并且可以使用 CMake 编译它,没有任何问题。效果很完美。

\n\n

现在,我想在用 C 编写的 main() 中添加一些 Ada 函数,并且我想通过 CMake 编译它。鉴于我无法使用 CMake 将我的 Ada 函数链接到主函数,我得到

\n\n
main.c:(.text.startup+0x16a): undefined reference to adainit\nmain.c:(.text.startup+0x179): undefined reference to adafunction\nmain.c:(.text.startup+0x190): undefined reference to adafinal\n
Run Code Online (Sandbox Code Playgroud)\n\n

我通过使用主函数(用 C 编写)调用唯一的 Ada 函数(我编写了该函数)进行了另一个简化测试,并使用以下命令编译了它

\n\n
gcc -c main.c\ngnatmake -c lib_ada.ali\ngnatbind -n lib_ada.ali\ngnatlink lib_ada.ali main.o -o exe\n
Run Code Online (Sandbox Code Playgroud)\n\n

效果很好。你知道我如何将这种方法集成到 CMakeList.txt 中吗?

\n\n

注意:我认为(也许我错了)我不能使用唯一的 gnatlink,因为我需要链接我已经拥有的所有其他功能。

\n\n

这里报告了一个最小的可重复示例。

\n\n

--- main.c ---

\n\n
#include <stdio.h>\n\nextern int adainit();\nextern int adafinal();\nextern int Add(int,int);\n\nint main()\n{\n    adainit();\n    printf ("Sum of 3 and 4 is: %d\\n", Add (3,4));\n    adafinal();\n\n    return 0;\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

--- lib_test.adb ---

\n\n
package body Lib_Test is\n    function Ada_Add (A, B : Integer) return Integer is\n    begin\n        return A + B;\n    end Ada_Add;\nend Lib_Test;\n
Run Code Online (Sandbox Code Playgroud)\n\n

--- lib_test.ads ---

\n\n
package Lib_Test is\n   function Ada_Add (A, B : Integer) return Integer;\n   pragma Export (C, Ada_Add, "Add");\nend Lib_Test;\n
Run Code Online (Sandbox Code Playgroud)\n\n

1\xc2\xb0测试:如果使用以下命令编译:

\n\n
gcc -c main.c\ngnatmake -c lib_test.adb\ngnatbind -n lib_test.ali\ngnatlink lib_test.ali main.o -o exe\n
Run Code Online (Sandbox Code Playgroud)\n\n

运行./exe你得到Sum of 3 and 4 is: 7

\n\n

2\xc2\xb0 测试:我尝试使用以下链接 *.a 的 CMake 文件 (CMakeLists.txt)

\n\n
cmake_minimum_required(VERSION 2.6)\nproject(Ada2C)\n\nenable_language(C)\n\nset(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} "${CMAKE_SOURCE_DIR}/cmake")\nset(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)\nset(CMAKE_VERBOSE_MAKEFILE ON)\nset(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -O3 -m64")\n\nfind_library(TEST_lib lib_test.a PATHS ${CMAKE_CURRENT_SOURCE_DIR})\nmessage(STATUS "Finding library: ${TEST_lib}")\nadd_executable(TEST_release ${CMAKE_CURRENT_SOURCE_DIR}/main.c)\ntarget_link_libraries(TEST_release ${TEST_lib})\n
Run Code Online (Sandbox Code Playgroud)\n\n

我为 Ada 函数生成库 lib_test.a

\n\n
gnatmake lib_test.adb\nar rc lib_test.a\n
Run Code Online (Sandbox Code Playgroud)\n\n

我运行cmakemake得到

\n\n
main.c:(.text.startup+0x16a): undefined reference to adainit\nmain.c:(.text.startup+0x179): undefined reference to adafunction\nmain.c:(.text.startup+0x190): undefined reference to adafinal\n
Run Code Online (Sandbox Code Playgroud)\n

fly*_*lyx 6

更多的是评论而不是答案,但评论太长了,所以这里是:

将 Ada 代码编译到二进制文件中意味着您的二进制文件需要访问 GNAT 运行时。gnatlink这是当您使用它链接最终可执行文件时所做的一件事。另一件事是生成的b~<something>.ad{s,b}源代码gnatbind,您需要对其进行编译和链接,正如其他人提到的那样。

到目前为止,我所见过的将 Ada 嵌入到 C 中的最简洁的方法是创建一个封装库。如果您的实际问题仅涉及一个 Ada 函数,那么这可能没有意义,但对于较大的 Ada 块却有意义。封装的库将是一个内置了 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;
Run Code Online (Sandbox Code Playgroud)

在 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)
Run Code Online (Sandbox Code Playgroud)

在您的 C 文件中,您可以删除与adainit()和相关的所有内容adafinal()