Linux 下c++程序一次编译到处运行

需求:项目通过一次编译出的程序要能够适配任何版本Linux发行版。

通过程序的编译运行原理可以知道有几个技术问题:

编译可执行程序需要依赖的本地库的版本必须低于目标机。
许多地方用到了C++语言11以及更高版本的新特性,所以编译器版本必须是新的。
但是一个Linux操作系统安装的默认gcc/g++依赖的是同版本的c/c++标准库。
通过寻找解决方案:

在高版本的Linux发行版上编译程序,然后把程序依赖的库都安装到目标机上,让程序寻找指定的库。

解决方案

优点:自由使用所需的Linux发行版,环境良好,开发调试都是随心所欲。

缺点:安装包会比前者多一些系统库,导致安装包较大。

通过衡量,我决定前期采用第二种方案,毕竟谁也不想在2019年还整天面对一个90年代的Linux操作系统。然后后期项目成熟以后,需要优化程序体积,才能派的上用场。

以下为第二种解决方案的要点,详情请参阅man手册:man 1 ld中 关于-rpath,-rpath-link,--dynamic-linker的选项:

编译时指定<可执行程序运行时查找动态链接器的路径>,给gcc/g++添加参数[使其自动传递给ld]: -Wl,--dynamic-linker=../lib64/ld-linux-x86-64.so.2
编译时指定<动态库运行时查找库的目录>,给gcc/g++添加参数[使其自动传递给ld]:-Wl,-rpath=$ORIGIN
编译时指定<可执行程序运行时查找库的目录>,给gcc/g++添加参数[使其自动传递给ld]:-Wl,-rpath=../lib64/
编译完成后把可执行程序放入bin目录,程序依赖的所有库和链接器放入lib64目录。
打包,并拷贝至目标机上解压,进入bin目录,执行可执行程序。
注:上述路径可根据不同环境适当调整。

 

 

以下为一个简单样例:

项目结构如下:

/root/Project
├── bin                             // 编译出的可执行程序放这里
├── lib64                          // 可执行程序依赖的所有库放这里
└── src                             // 源代码目录
    ├── demo                     // 主程序目录
    │   └── helloworld.cpp
    └── libsimple                // 一个动态库,被主程序依赖。
        ├── libsimple.cpp
        └── libsimple.h

其中 helloworld.cpp代码如下:

#include "libsimple.h"

int main(void)
{
    return print();
}

libsimple.h代码如下:

#ifndef LIB_SIMPLE
#define LIB_SIMPLE

extern int print();

#endif // LIB_SIMPLE

libsimple.cpp代码如下:

#include "libsimple.h"
#include <iostream>

int print()
{
    std::cout << "libsimple print" << std::endl;
    return 0;
}

 

首先编译libsimple.cpp成libsimple.so:

g++ /root/Project/src/libsimple/libsimple.cpp -o /root/Project/lib64/libsimple.so -shared -fPIC -Wl,-rpath=../lib64/ -Wl,-rpath=$ORIGIN

然后编译helloworld.cpp成可执行程序hw:

g++ /root/Project/src/demo/helloworld.cpp -I /root/Project/src/libsimple -L /root/Project/lib64 -lsimple -o /root/Project/bin/hw -Wl,-rpath=../lib64/ -Wl,--dynamic-linker=../lib64/ld-linux-x86-64.so.2

接着把hw依赖的所有库都拷贝至/root/Project/lib64目录:

例如我的环境下

 ldd /root/Project/bin/hw
    linux-vdso.so.1 =>  (0x00007fff553fb000)
    libsimple.so => ../lib64/libsimple.so (0x00007fdd63ae3000)
    libstdc++.so.6 => /lib64/libstdc++.so.6 (0x00007fdd637d5000)
    libm.so.6 => /lib64/libm.so.6 (0x00007fdd634d3000)
    libgcc_s.so.1 => /lib64/libgcc_s.so.1 (0x00007fdd632bd000)
    libc.so.6 => /lib64/libc.so.6 (0x00007fdd62eef000)
    ../lib64/ld-linux-x86-64.so.2 => /lib64/ld-linux-x86-64.so.2 (0x0000556098101000)

可以看到依赖了5个动态库,和1个链接器。(linux-vdso.so.1不需要拷贝) 把它们拷贝成功:

cp /lib64/libstdc++.so.6 /root/Project/lib64  
cp /lib64/libm.so.6 /root/Project/lib64 
cp /lib64/libgcc_s.so.1 /root/Project/lib64 
cp /lib64/libc.so.6 /root/Project/lib64 
cp /lib64/ld-linux-x86-64.so.2 /root/Project/lib64 

此时Project目录应该如下:

/root/Project
├── bin
│   └── hw
├── etc
├── lib64
│   ├── ld-linux-x86-64.so.2
│   ├── libc.so.6
│   ├── libgcc_s.so.1
│   ├── libm.so.6
│   ├── libsimple.so
│   └── libstdc++.so.6
└── src
    ├── demo
    │   └── helloworld.cpp
    └── libsimple
        ├── libsimple.cpp
        └── libsimple.h

现在就可以打包了,记得不要把src目录打进包里。

拷贝至任意目标机上解压,进入bin目录执行./hw

输出如下:

libsimple print

我们一次编译后的程序即可在任何Linux发行版上运行!
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值