Наши проекты:
Журнал · Discuz!ML · Wiki · DRKB · Помощь проекту |
||
ПРАВИЛА | FAQ | Помощь | Поиск | Участники | Календарь | Избранное | RSS |
[3.133.86.172] |
|
Сообщ.
#1
,
|
|
|
Добрый день!
У меня есть библиотека на С, вызывающая ассемблерную функцию: #define EXPORT __attribute__((visibility("default"))) EXPORT int foo(void); int foo(void) { extern int _start(); return 1; } Как написать динамическую библиотеку-обёртку на C++ для вызова через неё функции на С и как её компилировать с помощью GCC? Спасибо. |
Сообщ.
#2
,
|
|
|
Цитата Sunless @ Как написать динамическую библиотеку-обёртку на C++ для вызова через неё функции на С и как её компилировать с помощью GCC? Не понял.. В чём именно проблема - в создании dll или вызове функции из библиотеки "C" из программы на C++ ? |
Сообщ.
#3
,
|
|
|
Предыстория вопроса.
Есть программа на ассемблере для Linux .text .globl _start _start: movq $231, %rax movq $1, %rdi syscall Есть программа на С, использующая программу на ассемблере и компилируемая GCC в shared library. #define EXPORT __attribute__((visibility("default"))) EXPORT int foo(void); int foo(void) { extern int _start(); return _start(); } Цель - написать прослойку на С++ в виде shared library с компиляцией GCC, которая бы прокидывала вызов к себе из C# в функцию библиотеки на С. В C# вызов такой using System.Runtime.InteropServices; class Program{ [DllImport("lib.so")] public static extern int foo (); static void Main(string[] args) { int code = foo(); System.Console.WriteLine(code); } } Я посмотрел в интернете, но, кроме extern "C", информации не нашел. |
Сообщ.
#4
,
|
|
|
Цитата Sunless @ Я посмотрел в интернете, но, кроме extern "C", информации не нашел. Так и есть. И я так делал. Пишем модуль с функциями приблизительно так: //--------------------------------------------------------------------------- // file boostintmod.cpp 2018.09.12 //--------------------------------------------------------------------------- #include "stdafx.h" #include "project.h" // какие-то инклюды //--------------------------------------------------------------------------- extern "C" { int install (int argc,char* argv[]); int uninstall (void); void SetTest (bool bT); // _init() - будет вызвана при инициализации динамической библиотеки (загрузки ее в память); int _init (void); // _fini() - будет вызвана при выгрузке из памяти динамической библиотеки. int _fini (void); } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- int _init() { int iRetC=-1; // что-то делаем return iRetC; } //--------------------------------------------------------------------------- int _fini() { int iRetC=-1; // что-то делаем return iRetC; } //--------------------------------------------------------------------------- void SetTest(bool bT) { // что-то делаем } //--------------------------------------------------------------------------- int install (int argc,char* argv[]) { // что-то делаем return iRetC; } //--------------------------------------------------------------------------- int uninstall (void) { // что-то делаем return iRetC; } Дальше собираем .so файл и всё |
Сообщ.
#5
,
|
|
|
Библиотека на С инклюдами не подключается у меня, либо что-то не так собираю. МОжете привести полную команду сборки для всех 3 файлов привести для Linux?
Добавлено На данный момент я собираю библиотеку С командой Цитата , а затем вызываю её, как показано в коде C#. gcc -shared -fpic -o lib.so my.c asm.s Добавлено extern "C" { int foo(); } Это весь код, который требуется в файле .cpp для моего случая? Как включить в сборку библиотеку на С? Добавлено Сборка с #include "lib.so" Цитата g++ -shared -fpic -o lib.so my.cpp |
Сообщ.
#6
,
|
|
|
Цитата Sunless @ Библиотека на С инклюдами не подключается у меня, либо что-то не так собираю. МОжете привести полную команду сборки для всех 3 файлов привести для Linux? Как собрать .so библиотеку легко найти в Сети. Но мне этого было не достаточно, поскольку надо было собирать проект из нескольких библиотек и массы файлов. Поэтому я на основе статьи: gnumake Сделал себе makefile. Который позволяет собирать приложение из нескольких директорий. 1. Все файлы в каждой директории компилируются и заносятся в свою статическую библиотеку. 2. После этого все статические библиотеки подключаются при сборке. При этом только необходимые для конкретной сборки модули извлекаются из библиотек - так работает линкер. 3. Для добавления нового модуля в проект (и статическую библиотеку) достаточно его скопировать в соотв. директорию. Для .so - библиотеки получился такой makefile: Скрытый текст # # file makefile 2018.04.07 # # Все файлы проекта в нескольких директориях # Все файлы в каждой директории - файлы проекта # # #------------------------------------------------------- # Compiler name # CC := g++ #------------------------------------------------------- # Result # PNAME := boostintdll.so #------------------------------------------------------- # Модули c интерфейсными функциями dll # #DLLINTERFACE := dllmod1 dllmod2 DLLINTERFACE := boostintmod #------------------------------------------------------- # mkf name - сделаем сборку зависимой от изменения # и .mkf-файла тоже # MN := makefile #------------------------------------------------------- # директории для поиска файлов # source_dir1 := . source_dir2 := ../gen source_dir2p := ../gen/ source_dir3 := ../boost source_dir3p := ../boost/ source_dirs := $(source_dir1) $(source_dir2) $(source_dir3) # поиск хеадеров (сначала в своей директории): search_h1 := $(source_dir1) $(source_dir2) $(source_dir3) search_h2 := $(source_dir2) search_h3 := $(source_dir3) $(source_dir2) # search_sources := $(addsuffix /*.cpp,$(source_dirs)) search_dir1 := $(addsuffix /*.cpp,$(source_dir1)) search_dir2 := $(addsuffix /*.cpp,$(source_dir2)) search_dir3 := $(addsuffix /*.cpp,$(source_dir3)) #------------------------------------------------------- # LIBs # LIBS := -lpthread -lrt -nostdlib LIBPRJ := libut.a LIBG := $(addsuffix /libg.a,$(source_dir2)) LIBI := $(addsuffix /libb.a,$(source_dir3)) #------------------------------------------------------- # Опции компилера # CFLAGS := -Wall -W -Werror -pipe -O2 -fexceptions --static -c -MMD -fPIC #------------------------------------------------------- # Опции линкера # LFLAGS := -Wall -pipe -L/usr/lib -L/usr/lib/nptl -D_REENTRANT -s -shared #------------------------------------------------------- # общая цель - состоит в данном случае из 3-х целей # 1. статическая библиотека $(LIBG) # 2. статическая библиотека $(LIBI) # 3. программа $(PNAME) с использованием этих библиотек # .PHONY : all all: $(LIBG) $(LIBI) $(PNAME) #------------------------------------------------------- # библиотеку $(LIBG) сделаем из файлов в директории # $(source_dir2) # $(LIBG): $(MN) $(LIBG): $(patsubst %.cpp,%.o,$(wildcard $(search_dir2))) VPATH := $(source_dir2) $(addprefix $(source_dir2p),%.o): $(addprefix $(source_dir2p),%.cpp) $(MN) $(CC) $(CFLAGS) $(addprefix -I ,$(search_h2)) $< -o $@ ar cr $(LIBG) $@ #------------------------------------------------------- include $(wildcard $(addprefix $(source_dir2p),*.d)) #------------------------------------------------------- # библиотеку $(LIBI) сделаем из файлов в директории # $(source_dir3) # $(LIBI): $(MN) $(LIBI): $(patsubst %.cpp,%.o,$(wildcard $(search_dir3))) VPATH := $(source_dir3) $(addprefix $(source_dir3p),%.o): $(addprefix $(source_dir3p),%.cpp) $(MN) $(CC) $(CFLAGS) $(addprefix -I ,$(search_h3)) $< -o $@ ar cr $(LIBI) $@ #------------------------------------------------------- include $(wildcard $(addprefix $(source_dir3p),*.d)) #------------------------------------------------------- #------------------------------------------------------- # $< - 1 param, $^ - all params, $@ - target # запуск линкера - собираем результат из библиотек и .o файлов # $(PNAME): $(LIBG) $(PNAME): $(LIBI) $(PNAME): $(LIBPRJ) $(PNAME): $(MN) $(PNAME): $(notdir $(patsubst %.cpp,%.o,$(wildcard $(search_sources)))) $(CC) $(LFLAGS) $(addsuffix .o,$(DLLINTERFACE)) $(LIBPRJ) $(LIBI) $(LIBG) $(LIBS) -o $@ #------------------------------------------------------- # установим путь для поиска файлов # VPATH := $(source_dir1) : $(source_dir2) : $(source_dir3) %.o: %.cpp $(MN) $(CC) $(CFLAGS) $(addprefix -I ,$(source_dirs)) $< #....................................................... # укажем зависимости, сгенерированне компилером # include $(wildcard *.d) #....................................................... # внесём все .o файлы директории $(source_dir1) в библиотеку проекта $(LIBPRJ) # $(LIBPRJ): $(notdir $(patsubst %.cpp,%.o,$(wildcard $(search_dir1)))) ar cr $@ *.o #------------------------------------------------------- # .PHONY : clean clean: rm -f *.o *.d #------------------------------------------------------- Ты уж сам смотри, что тебе нужно. Можно собрать статическую библиотеку С отдельно, и просто подключить её при сборке c++ проекта, передав линкеру в качестве параметра. |
Сообщ.
#7
,
|
|
|
Спасибо. Пока скрипт сложноват. Надо почитать статью.
Я сделал такой код extern "C" { #define EXPORT __attribute__((visibility("default"))) EXPORT int foocpp(void) { int foo(); return foo(); } } И собираю так Цитата g++ -shared -fpic -o lib.so my.cpp my.c asm.s Но при запуске dotnet run получаю symbol lookup error: .../bin/Debug/netcoreapp3.1/lib.so: undefined symbol: foo |
Сообщ.
#8
,
|
|
|
Трудно сходу сказать, что у тебя не получается.
Легче сделать самому, а потом рассказать - как. Только с ассемблером я не работаю, это ты сам делай. 1. Сделаем модуль на С и поместим его в статическую библиотеку: //--------------------------------------------------------------------------- // file test.c 2020.09.19 //--------------------------------------------------------------------------- // gcc -c test.c // ar cr xxmm.a test.o //--------------------------------------------------------------------------- #include <stdio.h> //--------------------------------------------------------------------------- int TypeTest (const char* pStr) { if(!pStr) return -1; printf ("function=%s pStr=%s\n",__FUNCTION__,pStr); return 0; } //--------------------------------------------------------------------------- ------ Скомпилируем и добавим в статическую библиотеку xxmm.a: gcc -c test.c ar cr xxmm.a test.o ------ Напишем исходник .so и соберём его вместе с библиотекой xxmm.a: //--------------------------------------------------------------------------- // file testdll.cpp 2020.09.19 //--------------------------------------------------------------------------- #include <stdio.h> //--------------------------------------------------------------------------- extern "C" { int DllTest (const char* pStr); int TypeTest (const char* pStr); //void _init() - будет вызвана при инициализации динамической библиотеки (загрузки ее в память); //int _init (void); //void _fini() - будет вызвана при выгрузке из памяти динамической библиотеки. //int _fini (void); } //--------------------------------------------------------------------------- //export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:. //--------------------------------------------------------------------------- /* int _init() { return iRetC; } */ //--------------------------------------------------------------------------- /* int _fini() { return iRetC; } */ //--------------------------------------------------------------------------- int DllTest(const char* pStr) { return TypeTest (pStr); } //--------------------------------------------------------------------------- ------ сборка so: g++ -c -fPIC testdll.cpp g++ -D_REENTRANT -s -shared testdll.o xxmm.a -o testdll.so ------ Теперь сделаем тест, который испытает библиотеку: //--------------------------------------------------------------------------- // file checkdll.cpp 2020.09.19 //--------------------------------------------------------------------------- #include <stdio.h> #include <dlfcn.h> //--------------------------------------------------------------------------- typedef int (*pDllTest) (const char* pStr); //--------------------------------------------------------------------------- int InstallSo (void); int UnInstallSo (void); int MainWork (int argc,char *argv[]); //--------------------------------------------------------------------------- void* libHWND = NULL; pDllTest DllTest = NULL; //--------------------------------------------------------------------------- // укажем текущую директорию для поиска динамической библиотеки: export LD_LIBRARY_PATH=. // или укажем полный путь к библиотеке const char* pDllLibName = "testdll.so"; // имя динамической библиотеки //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- int main(int argc,char *argv[]) { printf("--- main (checkdll test) v1.0 2019.09.19 ---\n"); int iRetLib = -1; int iRetC = -1; for(int i=0;i==0;++i,iRetC=0) { iRetLib = InstallSo(); if(iRetLib < 0) break; printf("Install .so - OK!\n"); iRetC = MainWork(argc,argv); if(iRetC < 0) break; } UnInstallSo(); return iRetC; } //--------------------------------------------------------------------------- //--------------------------------------------------------------------------- int InstallSo(void) { int iRetC = 1; for(int i=0;i==0;++i,iRetC=0) { //загрузка библиотеки libHWND = ::dlopen(pDllLibName, RTLD_LAZY);//RTLD_LAZY);RTLD_NOW); if(!libHWND) { printf("dlopen() error: %s\n", dlerror()); iRetC = -1; break; } //ищем в библиотеке требуемые процедуры DllTest = (pDllTest)::dlsym(libHWND, "DllTest"); if(!DllTest) { printf("found DllTest error: %s\n", dlerror()); iRetC = -2; break; } } return iRetC; } //--------------------------------------------------------------------------- int UnInstallSo(void) { int iRetC = 1; for(int i=0;i==0;++i,iRetC=0) { if(!libHWND) break; ::dlclose(libHWND); libHWND=NULL; } return iRetC; } //--------------------------------------------------------------------------- int MainWork(int argc,char *argv[]) { int iRetC=-1; if(DllTest) { iRetC = DllTest("MainWork"); // iRetC = DllTest(NULL); printf("iRetC=%d\n",iRetC); } return iRetC; } //--------------------------------------------------------------------------- ------ Сборка теста: g++ -c checkdll.cpp g++ -Wall -pipe -ldl -D_REENTRANT -s checkdll.o -o checkdll ------ Для удобства сделаем общий командный файл для сборки всего хозяйства: gcc -c test.c ar cr xxmm.a test.o g++ -c -fPIC testdll.cpp g++ -D_REENTRANT -s -shared testdll.o xxmm.a -o testdll.so g++ -c checkdll.cpp g++ -Wall -pipe -ldl -D_REENTRANT -s checkdll.o -o checkdll ------ У меня получилось. ------ Надо указать свою текущую директорию для поиска .so - библиотеки перед запуском теста: export LD_LIBRARY_PATH=. Или в исходнике указать полный путь библиотеки. ------ Ещё удобный вариант: 1. Узнаём полное имя запущенного приложения. 2. Извлекаем из него path 3. Добавляем к path имя библиотеки, тем самым получая полное её имя в текущей директории. 4. Всё, она загрузится. |