На главную Наши проекты:
Журнал   ·   Discuz!ML   ·   Wiki   ·   DRKB   ·   Помощь проекту
ПРАВИЛА FAQ Помощь Участники Календарь Избранное RSS
msm.ru
Модераторы: Qraizer, Hsilgos
  
> Библиотека на С++ для вызова библиотеки на С в Linux
    Добрый день!
    У меня есть библиотека на С, вызывающая ассемблерную функцию:
    ExpandedWrap disabled
          #define EXPORT __attribute__((visibility("default")))
              EXPORT int foo(void);
              int foo(void)
              {
                  extern int _start();
                  return 1;
              }


    Как написать динамическую библиотеку-обёртку на C++ для вызова через неё функции на С и как её компилировать с помощью GCC?
    Спасибо.
      Цитата Sunless @
      Как написать динамическую библиотеку-обёртку на C++ для вызова через неё функции на С и как её компилировать с помощью GCC?

      Не понял..
      В чём именно проблема - в создании dll или вызове
      функции из библиотеки "C" из программы на C++ ?
        Предыстория вопроса.
        Есть программа на ассемблере для Linux
        ExpandedWrap disabled
              .text
                 .globl _start
              
              _start:              
                 movq $231, %rax
                 movq $1, %rdi
                 syscall

        Есть программа на С, использующая программу на ассемблере и компилируемая GCC в shared library.
        ExpandedWrap disabled
              #define EXPORT __attribute__((visibility("default")))
                  EXPORT int foo(void);
                  int foo(void)
                  {
                      extern int _start();
                      return _start();
                  }

        Цель - написать прослойку на С++ в виде shared library с компиляцией GCC, которая бы прокидывала вызов к себе из C# в функцию библиотеки на С.
        В C# вызов такой
        ExpandedWrap disabled
          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", информации не нашел.
        Сообщение отредактировано: Sunless -
          Цитата Sunless @
          Я посмотрел в интернете, но, кроме extern "C", информации не нашел.

          Так и есть. И я так делал.
          Пишем модуль с функциями приблизительно так:
          ExpandedWrap disabled
            //---------------------------------------------------------------------------
            // 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 файл и всё
          Сообщение отредактировано: ЫукпШ -
            Библиотека на С инклюдами не подключается у меня, либо что-то не так собираю. МОжете привести полную команду сборки для всех 3 файлов привести для Linux?

            Добавлено
            На данный момент я собираю библиотеку С командой
            Цитата
            gcc -shared -fpic -o lib.so my.c asm.s
            , а затем вызываю её, как показано в коде C#.

            Добавлено
            ExpandedWrap disabled
              extern "C" {
              int foo();
              }

            Это весь код, который требуется в файле .cpp для моего случая? Как включить в сборку библиотеку на С?

            Добавлено
            Сборка с
            ExpandedWrap disabled
              #include "lib.so"
            не проходит командой
            Цитата
            g++ -shared -fpic -o lib.so my.cpp
              Цитата Sunless @
              Библиотека на С инклюдами не подключается у меня, либо что-то не так собираю. МОжете привести полную команду сборки для всех 3 файлов привести для Linux?

              Как собрать .so библиотеку легко найти в Сети.
              Но мне этого было не достаточно, поскольку надо было собирать
              проект из нескольких библиотек и массы файлов.
              Поэтому я на основе статьи:
              gnumake
              Сделал себе makefile.
              Который позволяет собирать приложение из нескольких директорий.
              1. Все файлы в каждой директории компилируются и заносятся в свою статическую библиотеку.
              2. После этого все статические библиотеки подключаются при сборке.
              При этом только необходимые для конкретной сборки модули извлекаются
              из библиотек - так работает линкер.
              3. Для добавления нового модуля в проект (и статическую библиотеку)
              достаточно его скопировать в соотв. директорию.
              Для .so - библиотеки получился такой makefile:
              Скрытый текст

              ExpandedWrap disabled
                #
                # 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++ проекта, передав линкеру в качестве параметра.
              Сообщение отредактировано: ЫукпШ -
                Спасибо. Пока скрипт сложноват. Надо почитать статью.
                Я сделал такой код
                ExpandedWrap disabled
                  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
                  Трудно сходу сказать, что у тебя не получается.
                  Легче сделать самому, а потом рассказать - как.
                  Только с ассемблером я не работаю, это ты сам делай.
                  1. Сделаем модуль на С и поместим его в статическую библиотеку:
                  ExpandedWrap disabled
                    //---------------------------------------------------------------------------
                    // 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:
                  ExpandedWrap disabled
                    //---------------------------------------------------------------------------
                    // 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
                  ------
                  Теперь сделаем тест, который испытает библиотеку:
                  ExpandedWrap disabled
                    //---------------------------------------------------------------------------
                    // 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. Всё, она загрузится.
                  Сообщение отредактировано: ЫукпШ -
                  0 пользователей читают эту тему (0 гостей и 0 скрытых пользователей)
                  0 пользователей:


                  Рейтинг@Mail.ru
                  [ Script execution time: 0,0526 ]   [ 16 queries used ]   [ Generated: 29.03.24, 01:08 GMT ]