web-dev-qa-db-ja.com

C / AdaコードのCMakeファイルにgnatmake / gnatbind / gnatlinkをどのように統合しますか?

いくつかの言語(C、C++、Fortran77、Fortran90)でコードを記述しましたが、CMakeを使用することで、なんら問題なくコンパイルできます。それは完璧に機能します。

ここで、Cで記述されたmain()といくつかのAda関数を追加し、CMakeでコンパイルしたいと思います。 CMakeを使用してAda関数をメイン関数にリンクできないとすると、

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

私がコーディングした唯一のAda関数を呼び出すmain関数(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°テスト:次のコマンドを使用してコンパイルした場合:

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°テスト:* .aをリンクする次のCMakeファイル(CMakeLists.txt)を使用しようとしました

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})

Ada関数のライブラリlib_test.aを生成します

gnatmake lib_test.adb
ar rc lib_test.a

cmakemakeを実行すると、

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
4
Matteo

回答よりもコメントの方が多いが、コメントには長すぎるため、次のようになります。

Adaコードをバイナリにコンパイルするということは、バイナリがGNATランタイムにアクセスする必要があることを意味します。これは、最終的な実行可能ファイルをリンクするために使用するときにgnatlinkが行うことの1つです。もう1つは_b~<something>.ad{s,b}_ source gnatbindが生成するもので、他の人が述べたようにコンパイルおよびリンクする必要があります。

これまでに見たAdaをCに埋め込む最もクリーンな方法は、encapsulatedライブラリを作成することです。これは、実際の問題が1つの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;
_

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()に関連するすべてを削除できます。

4
flyx