У меня возникли проблемы с переносом моей программы на Linux, поскольку Linux по умолчанию имеет общедоступный символ. В настоящее время у меня есть исполняемый файл и общая библиотека объектов .so, написанная в Ada. Они разделяют некоторые файлы, например таких:Как изменить видимость символов библиотек Ada с помощью gnat?
Общие/my_program_generic.ads
generic package My_Program_Generic is
Initialized : Boolean := False;
procedure Initialize;
end My_Program_Generic;
Общие/my_program_generic.adb
with Ada.Text_IO;
package body My_Program_Generic is
procedure Initialize is
begin
Ada.Text_IO.Put_Line("Initialized: " & Initialized'Img);
if not Initialized then
Initialized := True;
-- Do stuff
Ada.Text_IO.Put_Line("Did stuff!");
end if;
end Initialize;
end My_Program_Generic;
Общие/my_program.ads
with My_Program_Generic;
My_Program is new My_Program_Generic;
Оба исполняемый файл и библиотека затем вызывают My_Program.Initialize
из отдельного кода. выхода (первый & второй линия является исполняемой, третьим является библиотека):
Initialized: FALSE
Did stuff!
Initialized: TRUE
Проблема здесь состоит в том, что видимость символа является открытой, так что кажется, работает исполняемое эта функция и инициализирует все, но затем общий объект библиотека использует исполняемый файл My_Program.Initialized
(который является True), а не его собственный (который является False), не инициализируется, а затем сбой происходит с помощью неинициализированной переменной.
Я попытался компиляции с -fvisiblity=hidden
для компиляции все (как из Makefile и файл комар проекта (.gpr)), который, кажется, правильно передавая его компилятором (например, он показывает в командной строке gcc -c -fPIC -g -m32 -fvisibility=hidden -gnatA my_file.adb
), но он, похоже, не изменил ситуацию, и я не могу найти никакой документации для контроля видимости с помощью gnat.
Моей ОС является CentOS 5.6. Я не могу перейти на более новую версию Linux, но я мог бы обновить версии GCC или gnat до всего, что работает на CentOS 5.6. Мой GCC/комар версия следует:
$ gcc --version
gcc (GCC) 4.1.2 20080704 (Red Hat 4.1.2-50)
...
$ gnatls -v
GNATLS 4.1.2 20080704 (Red Hat 4.1.2-50)
...
Да, я знаю, что это говорит Red Hat, но я использую CentOS. AFAIK они абсолютно совместимы друг с другом в любом случае.
Возможно всю информацию, необходимую, чтобы решить мою проблему полностью пояснялось выше, но вот остальная часть кода, Makefiles и файлы GPR вы могли бы использовать, чтобы восстановить свои исполняемые файлы на вашем компьютере (для более полной, но менее минимальная иллюстрация).
Библиотека/my_library.ads
package My_Library is
procedure Initialize_Library;
pragma Export (DLL, Initialize_Library, "Initialize_Library");
end My_Library;
Библиотека/my_library.adb
with Ada.Text_IO;
with My_Program;
package body My_Library is
procedure Initialize_Library is
begin
Ada.Text_IO.Put_Line("Initializing Library...");
My_Program.Initialize;
end Initialize_Library;
end My_Library;
Библиотека/dummy.ads
package Dummy is
end Dummy;
Библиотека/my_library.gpr
project My_Library is
for source_dirs use (".","../Common");
for Library_Src_Dir use "include";
for object_dir use "obj";
for library_dir use "lib";
for library_name use "my_library";
for library_kind use "dynamic";
for library_interface use ("dummy");
for library_auto_init use "true;
-- Compile 32-bit
for library_options use ("-m32");
package compiler is
for default_switches ("Ada")
use ("-g", "-m32", "-fvisibility=hidden");
end compiler;
for Source_Files use (
"my_program_generic.ads",
"my_program_generic.adb",
"my_program.ads",
"dummy.ads",
"my_library.ads",
"my_library.adb");
end My_Library;
Library/Makefile
GNATMAKE=gnatmake
LDFLAGS=-shared
TARGETBASE=libMy_Library.so
GNATMAKEFLAGS=--RTS=/usr/lib/gcc/i386-redhat-linux/4.1.2
TARGET=Debug/$(TARGETBASE)
# Phony target so make all will work
.PHONY: all
all: $(TARGET)
SRCS = \
../Common/my_program_generic.ads \
../Common/my_program_generic.adb \
../Common/my_program.adb \
dummy.ads \
my_library.ads \
my_library.adb
CHOPPATH = chop
OBJPATH = obj
LIBPATH = lib
$(TARGET) : $(SRCS)
$(GNATMAKE) -Pmy_library $(GNATMAKEFLAGS)
mv $(LIBPATH)/$(TARGETBASE) $(TARGET)
# Phony target so make clean will work
.PHONY: clean
clean:
rm -rf $(TARGET) $(CHOPPATH)/*.ads $(CHOPPATH)/*.adb $(OBJPATH)/*.s $(OBJPATH)/*.o $(OBJPATH)/*.ads $(OBJPATH)/*.adb *.s $(LIBPATH)/*.so $(LIBPATH)/*.ali
Exe/my_exe.ADB
with Ada.Text_IO;
with My_Program;
with My_Library_Import;
procedure My_Exe is
begin
Ada.Text_IO.Put_Line("Begin main program.");
My_Program.Initialize;
My_Library_Import.Initialize_Library;
end My_Exe;
Exe/my_library_import.ads
package My_Library_Import is
procedure Initialize_Library;
private
type External_Initialize_Library_Type is access procedure;
pragma Convention (DLL_Stdcall, External_Initialize_Library_Type);
External_Initialize_Library : External_Initialize_Library_Type := null;
end My_Library_Import;
Exe/my_library_import.adb
with Ada.Text_IO;
with Ada.Unchecked_Conversion;
with System;
with Interfaces.C;
with Interfaces.C.Strings;
use type System.Address;
package body My_Library_Import is
Library_Handle : System.Address := System.Null_Address;
Library_Name : String := "../Library/Debug/libMy_Library.so";
-- Interface to libdl to load dynamically linked libraries
function dlopen(
File_Name : in Interfaces.C.Strings.Chars_Ptr;
Flag : in Integer) return System.Address;
pragma Import (C, dlopen);
function dlsym(
Handle : in System.Address;
Symbol : in Interfaces.C.Char_Array) return System.Address;
pragma Import (C, dlsym);
function dlerror return Interfaces.C.Strings.Chars_Ptr;
pragma Import (C, dlerror);
function External_Initialize_Library_Type_Import is new Ada.Unchecked_Conversion(
System.Address, External_Initialize_Library_Type);
procedure Initialize_Library is
Temp_Name : Interfaces.C.Strings.Chars_Ptr;
begin
-- Load Library
Temp_Name := Interfaces.C.Strings.New_Char_Array(Interfaces.C.To_C(Library_Name));
Library_Handle := dlopen(Temp_Name, 16#101#); -- RTLD_NOW (0x0001), RTLD_GLOBAL (0x0100)
Interfaces.C.Strings.Free(Temp_Name);
-- Check for Load Library failure (did we execute from the right place?)
if (Library_Handle = System.Null_Address) then
Ada.Text_IO.Put_Line("dlerror: " &
Interfaces.C.Strings.Value(dlerror));
return;
end if;
-- Get function access
External_Initialize_Library := External_Initialize_Library_Type_Import(
dlsym(Library_Handle, Interfaces.C.To_C("Initialize_Library")));
-- Initialize library itself
External_Initialize_Library.all;
end Initialize_Library;
end My_Library_Import;
Exe/Makefile
CC=gcc
LD=g++
GNATCHOP=gnatchop
GNATMAKE=gnatmake
RC=windres
INCLUDE_PATH = -I.
LDFLAGS=-largs -ldl -lpthread -rdynamic -lstdc++
TARGET_FILE=my_exe
GNATMAKEFLAGS=--RTS=/usr/lib/gcc/i386-redhat-linux/4.1.2
TARGET_PATH=Debug
TARGET=$(TARGET_PATH)/$(TARGET_FILE)
# Phony target so make all will work
.PHONY: all
all : $(TARGET)
SRCS = \
../Common/my_program_generic.ads \
../Common/my_program_generic.adb \
../Common/my_program.adb \
my_exe.adb \
my_library_import.ads \
my_library_import.adb
CHOPPATH = chop
OBJPATH = obj
$(TARGET) : $(SRCS)
$(GNATCHOP) $^ $(CHOPPATH) -w -r
rm -rf *.s
$(GNATMAKE) -m32 -j3 -g -gnatwA -fvisibility=hidden -D $(OBJPATH) -k $(CHOPPATH)/*.adb $(LDFLAGS) $(GNATMAKEFLAGS)
rm -rf b~$(TARGET_FILE).*
mv $(TARGET_FILE) $(TARGET)
# Phony target so make clean will work
.PHONY: clean
clean:
rm -rf $(TARGET) $(CHOPPATH)/*.ads $(CHOPPATH)/*.adb $(OBJPATH)/*.s $(OBJPATH)/*.o $(OBJPATH)/*.ads $(OBJPATH)/*.adb *.s
Я не использую файл GPR для исполняемого файла (Exe).
Выполнить программу из папки «Exe» с ./Debug/my_exe
, и полный выход с дополнительными файлами заключается в следующем:
$ ./Debug/my_exe
Begin main program.
Initialized: FALSE
Did Stuff!
Initializing Library...
Initialized: TRUE
Почему не 'Initialized' в частной части пакета, или даже в теле пакета? хотя мне может что-то не хватает в вопросе ... –
@BrianDrummond Перемещение булевых в тело пакета и перекомпиляция обоих двоичных файлов, похоже, ничего не изменили. Есть ли что-нибудь о вопросе, который я могу прояснить? –
Что вы подразумеваете под '_Generic'? Это в смысле Ады, или вы просто имеете в виду «какой-то случайный, но типичный пример»? –