V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
alphaprogrammer
V2EX  ›  C++

C/C++ 编译器如何在缺乏依赖库(只有头文件)的情况下正确编译?

  •  
  •   alphaprogrammer · Feb 24, 2020 · 5579 views
    This topic created in 2253 days ago, the information mentioned may be changed or developed.

    一份代码需要编译到几种不同的平台, 依赖一些第三方库,因为没有编译环境,只能采用交叉编译的方式, 有没有方法能解决这种问题?

    目前我知道的是通过 dlopen 的方式来处理,但是对代码改动较大,大家有什么其他更好的方法吗?

    Supplement 1  ·  Feb 24, 2020
    代码时编译出可执行文件,依赖一些标准的第三方库, 在 ubuntu 上直接用 apt 就可安装的
    31 replies    2020-02-26 13:03:18 +08:00
    fcten
        1
    fcten  
       Feb 24, 2020
    是动态库就可以,缺少静态库则无法编译成可执行文件
    shylockhg
        2
    shylockhg  
       Feb 24, 2020
    交叉编译为啥会会没有库文件?
    ai277014717
        3
    ai277014717  
       Feb 24, 2020
    -undefined dynamic_lookup 可以符号改成动态查找。可以试试
    chinuno
        4
    chinuno  
       Feb 24, 2020 via Android
    创建 stub 的 so 文件,编译的时候用 stub 链接
    hitmanx
        5
    hitmanx  
       Feb 24, 2020
    把 dlopen 这层逻辑封装一下,上层不需要知道调用的库函数是哪里来的。dlopen 这一层可以用代码生成
    chinuno
        6
    chinuno  
       Feb 24, 2020 via Android
    第三方库你还是乖乖的交叉编译都编译出来吧
    alphaprogrammer
        7
    alphaprogrammer  
    OP
       Feb 24, 2020
    @shylockhg 因为本地没有编译平台,只有一个交叉编译器
    alphaprogrammer
        8
    alphaprogrammer  
    OP
       Feb 24, 2020
    @fcten 但是 gcc/g++ 在链接阶段会查找可执行程序引用到的所有函数,如果找不到会报错的吧
    littlewing
        9
    littlewing  
       Feb 24, 2020
    编译不需要库,只需要头文件
    链接阶段才需要库
    alphaprogrammer
        10
    alphaprogrammer  
    OP
       Feb 24, 2020
    @hitmanx 目前是在这方面想,但是我希望是 动态链接的方式和 dlopen 的方式能随意切换
    alphaprogrammer
        11
    alphaprogrammer  
    OP
       Feb 24, 2020
    @littlewing 这个我知道,现在就是需要编译可执行文件
    alphaprogrammer
        12
    alphaprogrammer  
    OP
       Feb 24, 2020
    @chinuno 这个思路不错,之前的代码可以原封不动,不用改
    alphaprogrammer
        13
    alphaprogrammer  
    OP
       Feb 24, 2020
    @ai277014717 gcc/g++ 有这个编译选项吗?
    hitmanx
        14
    hitmanx  
       Feb 24, 2020
    @alphaprogrammer 控制链接时要不要链接你这个 dlopen 层就可以了,拿个 build flag 控制一下
    ysc3839
        15
    ysc3839  
       Feb 24, 2020 via Android
    在 Windows 中可以把 DLL 等信息写入导入表中,自己的代码就不需要手动进行 LoadLibrary 等操作了。
    我印象中 Linux 也有类似机制的,用这种机制就不需要自己手动 dlopen 了。
    augustheart
        16
    augustheart  
       Feb 24, 2020
    要么老老实实 dlopen,要么老老实实把三方库都交叉编译一遍。
    augustheart
        17
    augustheart  
       Feb 24, 2020
    你要用别的奇怪方法,就不怕碰到动态库版本不对?
    SPACELAN
        18
    SPACELAN  
       Feb 24, 2020
    既然依赖库都要交叉编译了,不如一起静态链接吧
    alphaprogrammer
        19
    alphaprogrammer  
    OP
       Feb 24, 2020
    @SPACELAN 依赖库不由我提供, 直接从特定源下载即可
    alphaprogrammer
        20
    alphaprogrammer  
    OP
       Feb 24, 2020
    @augustheart 版本确实是一个问题,但是动态链接一样会碰到版本问题,这个是 code 应该做兼容处理的
    alphaprogrammer
        21
    alphaprogrammer  
    OP
       Feb 24, 2020
    @hitmanx 目前在这方面尝试,dlopen 之类的壳代码不知道有没有什么方法能自动生成的
    alphaprogrammer
        22
    alphaprogrammer  
    OP
       Feb 24, 2020
    @ysc3839 -_-!! 对 window 不了解,没接触过。
    SPACELAN
        23
    SPACELAN  
       Feb 24, 2020
    @alphaprogrammer #19 静态兼容性好很多,也方便别人直接运行
    neighbads
        24
    neighbads  
       Feb 24, 2020
    接口不多的话 写个假的 lib,只有导出函数没有功能的。。
    ysc3839
        25
    ysc3839  
       Feb 24, 2020 via Android
    @alphaprogrammer https://www.cprogramming.com/tutorial/shared-libraries-linux-gcc.html
    帮你找到了,Linux 也有这个功能,而且 gcc 可以直接识别 .so 文件,不像 Windows 需要一个 stub lib。
    chinuno
        26
    chinuno  
       Feb 24, 2020 via Android
    系统的包管理器不是这样用的。。
    那上面的库是为了维护系统内的依赖用的。你要用上面的库应该目标系统上安装 dev 包在目标系统上编译才能用这些库。
    另外一种用到包管理器里面库的情况是源维护者自己编译软件包的时候用到,一般也是维护者交叉编译对应库链接过去的。
    自己另外编译还强行用这些库很容易依赖被破坏。包管理器安装的软件一般没出问题是因为有维护者一直在更新依赖,就算是这样有时候还是会出现依赖问题。
    如果你只是要在对应系统发布可执行程序,最好的做法是每个平台编译对应的静态库,发布的时候发布静态连接的可执行程序。如果需要源码发布就附带每个平台的静态库一起发布。
    augustheart
        27
    augustheart  
       Feb 24, 2020
    @alphaprogrammer 甚至平台不同也会碰到问题的。每个平台的实现可能不同。基本上来说就是靠运气编程
    FrankHB
        28
    FrankHB  
       Feb 25, 2020
    @SPACELAN 静态链接兼容性一样要看节操,谁给你保证更好的。
    更没法变通才是真的。
    另外 Win32 上嘛,静态库里糊个 main 进去还可能让链接器找不到入口……
    FrankHB
        29
    FrankHB  
       Feb 25, 2020
    Ubuntu 用的第三方库,本来就没给你打算交叉编译来用。问题是你自己搞不到源码直接自己编译?
    退一步讲,就这些库的节操……真用,跑个虚拟机搞个环境都比你搞交叉编译省事。
    SPACELAN
        30
    SPACELAN  
       Feb 25, 2020
    @FrankHB #28 参考 Golang
    alphaprogrammer
        31
    alphaprogrammer  
    OP
       Feb 26, 2020
    说一下情况,就是原本写的代码时基于 x86 的,现在需要在 arm 上跑,依赖于一些第三方库(在目标机上可以直接 apt 安装)。目前由于没有 arm 环境,只能在 x86 上使用交叉编译的方式编译出 arm 可执行程序,第三方库依赖采用 dlopen 的方式去除依赖。(如果能下载 arm 版的第三方库 binary,也可以直接编译的)

    目前我的实现方式有点取巧,个人感觉实现方式不太好。

    首先,之前实现的代码都定义在一个 namespace A 下,
    假定依赖一个 func_b,其类型为 type_func_b, 在 namespace A 下定义一个 type_func_b 的变量 func_b,变量名与函数名相同,通过__attribute__(constructor)初始化 func_b 变量,指向第三方库中的函数符号。

    这样以前的代码基本不需要改,只需要根据编译 include 一个头文件即可。
    有一个缺点就是必须定义在同一个 namespace 下,否则变量 func_b 会与第三方库中的函数声明冲突
    About   ·   Help   ·   Advertise   ·   Blog   ·   API   ·   FAQ   ·   Solana   ·   2958 Online   Highest 6679   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 52ms · UTC 00:29 · PVG 08:29 · LAX 17:29 · JFK 20:29
    ♥ Do have faith in what you're doing.