V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
hhhhhh123
V2EX  ›  C

c++ 在服务器上打包 so 文件问题

  •  
  •   hhhhhh123 · 2022-07-29 11:25:55 +08:00 · 2256 次点击
    这是一个创建于 853 天前的主题,其中的信息可能已经有所发展或是发生改变。
    extern "C" __declspec(dllexport) float * OMP_EVAL(char* p1, char* p2, char* p3, char* p4, char* p5, char* p6, char* p7, char* p8, char* p9,
    	char* _board, char* _dead, bool eval_or_monte_carlo
    ){
      // 省略函数里面代码..
    }
    

    上面这串导出代码 我在 win 本地是能编译成 dll 动态库的, 但是在服务器上面编译就报错了

    main.cpp:13:22: error: expected constructor, destructor, or type conversion before ‘(’ token
       13 | extern "C" __declspec(dllexport) float * OMP_EVAL(char* p1, char* p2, char* p3, char* p4, char* p5, char* p6, char* p7, char* p8, char* p9,
          |                      ^
    make: *** [Makefile:25: hongyu] Error 1
    
    16 条回复    2022-07-30 21:24:32 +08:00
    nifury
        1
    nifury  
       2022-07-29 11:34:08 +08:00
    hmm 大概是 gcc 不支持__declspec(dllexport)?
    能编译成 dll 不代表能编译成 so 啊
    hhhhhh123
        2
    hhhhhh123  
    OP
       2022-07-29 11:35:31 +08:00
    ```
    g++ -O3 -std=c++11 -Wall -Wpedantic -pthread -c -o omp/CardRange.o omp/CardRange.cpp
    g++ -O3 -std=c++11 -Wall -Wpedantic -pthread -c -o omp/CombinedRange.o omp/CombinedRange.cpp
    g++ -O3 -std=c++11 -Wall -Wpedantic -pthread -c -o omp/EquityCalculator.o omp/EquityCalculator.cpp
    g++ -O3 -std=c++11 -Wall -Wpedantic -pthread -c -o omp/HandEvaluator.o omp/HandEvaluator.cpp
    ar rcs lib/ompeval.a omp/CardRange.o omp/CombinedRange.o omp/EquityCalculator.o omp/HandEvaluator.o
    g++ -O3 -std=c++11 -Wall -Wpedantic -pthread -shared -o hongyu.so main.cpp benchmark.cpp lib/ompeval.a
    /usr/bin/ld: lib/ompeval.a(HandEvaluator.o): warning: relocation against `_ZN3omp13HandEvaluator8cardInitE' in read-only section `.text.startup'
    /usr/bin/ld: /tmp/ccUEKBa8.o: relocation R_X86_64_PC32 against symbol `_ZSt4cout@@GLIBCXX_3.4' can not be used when making a shared object; recompile with -fPIC
    /usr/bin/ld: final link failed: bad value
    collect2: error: ld returned 1 exit status
    make: *** [Makefile:25: hongyu] Error 1
    ```
    qbqbqbqb
        3
    qbqbqbqb  
       2022-07-29 11:35:47 +08:00
    GCC 编译器是没有__declspec(dllexport)的,建议用 ifdef 控制一下
    hhhhhh123
        4
    hhhhhh123  
    OP
       2022-07-29 11:35:59 +08:00
    @nifury 你知道这个错误吗? 我吧 extern "C" __declspec(dllexport) 删掉了
    hhhhhh123
        5
    hhhhhh123  
    OP
       2022-07-29 11:36:23 +08:00
    @qbqbqbqb 我删除 extern "C" __declspec(dllexport) 这个了,但是出现了上面的错误, 你知道吗
    qbqbqbqb
        6
    qbqbqbqb  
       2022-07-29 11:37:01 +08:00
    @hhhhhh123 编译 so 的时候要加-fPIC 参数
    qbqbqbqb
        7
    qbqbqbqb  
       2022-07-29 11:37:40 +08:00
    extern "C"不要随便删,只删__declspec(dllexport)
    qbqbqbqb
        8
    qbqbqbqb  
       2022-07-29 11:43:26 +08:00
    @hhhhhh123 这个错误和 ompeval.a 这个静态库有关。一般情况下静态库和 so 动态库是不能混用的,除非静态库编译的时候加了-fPIC 参数才可以。如果可以的话就重新编译这个静态库。
    qbqbqbqb
        9
    qbqbqbqb  
       2022-07-29 11:51:42 +08:00   ❤️ 1
    如果无法重新编译静态库的话,可以考虑改符号导出。需要保证接口函数(原来的加了 dllexport 的函数)里面不能直接调用 ompeval.a 静态库里的函数。

    dllexport 在 Linux 环境的类似物是__attribute__ ((visibility ("default")))和__attribute__ ((visibility ("hidden")))。但是 GCC 默认选项是 default ,相当于默认全部 dllexport ,这里需要隐藏一些内部实现。

    有两种方法:
    第一种方法是编译加参数-fvisibility=hidden 修改为类似 Windows DLL 的默认不导出,然后在原来的 dllexport 的函数上加__attribute__ ((visibility ("default")))
    第二种方法是给用到了 ompeval.a 静态库的内部函数加__attribute__ ((visibility ("hidden")))
    hhhhhh123
        10
    hhhhhh123  
    OP
       2022-07-29 12:02:40 +08:00
    @nifury @qbqbqbqb
    @qbqbqbqb 我加了-fPIC 参数, 虽然能编译, 但是函数好像没有导出, 这个时候 应该怎么导出
    yolee599
        11
    yolee599  
       2022-07-29 12:35:25 +08:00 via Android
    执行下面这个指令看看有没有导出?
    nm -D <your .so file>
    hhhhhh123
        12
    hhhhhh123  
    OP
       2022-07-29 13:47:35 +08:00
    @yolee599 0000000000006710 T OMP_EVAL
    w _ITM_deregisterTMCloneTable
    w _ITM_registerTMCloneTable
    U _Unwind_Resume@GCC_3.0
    0000000000007c40 T _Z9benchmarkv
    000000000000b460 T _ZN3omp13CombinedRange10joinRangesERKSt6vectorIS1_ISt5arrayIhLm2EESaIS3_EESaIS5_EEm
    000000000000ad90 T _ZN3omp13CombinedRange7shuffleEv
    000000000000ae90 T _ZN3omp13CombinedRangeC1EjRKSt6vectorISt5arrayIhLm2EESaIS3_EE
    000000000000ad00 T _ZN3omp13CombinedRangeC1Ev
    000000000000ae90 T _ZN3omp13CombinedRangeC2EjRKSt6vectorISt5arrayIhLm2EESaIS3_EE
    000000000000ad00 T _ZN3omp13CombinedRangeC2Ev
    0000000000014930 T _ZN3omp13HandEvaluator10staticInitEv
    00000000000164c0 R _ZN3omp13HandEvaluator11FLUSH_RANKSE
    0000000000026460 B _ZN3omp13HandEvaluator11ORIG_LOOKUPE
    0000000000022460 B _ZN3omp13HandEvaluator12FLUSH_LOOKUPE
    00000000000147f0 T _ZN3omp13HandEvaluator14populateLookupEmjjjjjjb



    还有很多这样的 , 次数超过限制所有发不出来
    hhhhhh123
        13
    hhhhhh123  
    OP
       2022-07-29 13:49:01 +08:00
    解决了 extern "C" 我删掉了 忘记加上去了, 所以没有导出来, 加上后 重新编译 函数也能导出来了。
    proxytoworld
        14
    proxytoworld  
       2022-07-29 13:52:17 +08:00
    我用 cmake ,windows + gcc 编译成功..
    环境 windows + cmake + gcc 8.1.0 seh
    ![]( )
    proxytoworld
        15
    proxytoworld  
       2022-07-29 13:52:57 +08:00
    看错了,得编译 so
    buffzty
        16
    buffzty  
       2022-07-30 21:24:32 +08:00
    加个 LIB_API 宏定义
    #if defined WIN32 && !defined(BUFF_STATIC)
    #ifdef LIB_EXPORTS
    #define LIB_API __declspec(dllexport)
    #else
    #define LIB_API __declspec(dllimport)
    #endif
    #else
    #define LIB_API
    #endif
    #ifdef __cplusplus
    extern "C" {
    #endif
    LIB_API void libFn1();

    #ifdef __cplusplus
    }
    #endif
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   实用小工具   ·   3102 人在线   最高记录 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 29ms · UTC 13:47 · PVG 21:47 · LAX 05:47 · JFK 08:47
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.