我用几种语言(C、C++、Fortran77、Fortran90)编写了代码,并且可以使用 CMake 编译它,没有任何问题。效果很完美。
\n\n现在,我想在用 C 编写的 main() 中添加一些 Ada 函数,并且我想通过 CMake 编译它。鉴于我无法使用 CMake 将我的 Ada 函数链接到主函数,我得到
\n\nmain.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\nRun Code Online (Sandbox Code Playgroud)\n\n我通过使用主函数(用 C 编写)调用唯一的 Ada 函数(我编写了该函数)进行了另一个简化测试,并使用以下命令编译了它
\n\ngcc -c main.c\ngnatmake -c lib_ada.ali\ngnatbind -n lib_ada.ali\ngnatlink lib_ada.ali main.o -o exe\nRun 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}\nRun Code Online (Sandbox Code Playgroud)\n\n--- lib_test.adb ---
\n\npackage 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;\nRun Code Online (Sandbox Code Playgroud)\n\n--- lib_test.ads ---
\n\npackage Lib_Test is\n function Ada_Add (A, B : Integer) return Integer;\n pragma Export (C, Ada_Add, "Add");\nend Lib_Test;\nRun Code Online (Sandbox Code Playgroud)\n\n1\xc2\xb0测试:如果使用以下命令编译:
\n\ngcc -c main.c\ngnatmake -c lib_test.adb\ngnatbind -n lib_test.ali\ngnatlink lib_test.ali main.o -o exe\nRun Code Online (Sandbox Code Playgroud)\n\n运行./exe你得到Sum of 3 and 4 is: 7。
2\xc2\xb0 测试:我尝试使用以下链接 *.a 的 CMake 文件 (CMakeLists.txt)
\n\ncmake_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})\nRun Code Online (Sandbox Code Playgroud)\n\n我为 Ada 函数生成库 lib_test.a
\n\ngnatmake lib_test.adb\nar rc lib_test.a\nRun Code Online (Sandbox Code Playgroud)\n\n我运行cmake并make得到
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\nRun Code Online (Sandbox Code Playgroud)\n
更多的是评论而不是答案,但评论太长了,所以这里是:
将 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()。