Iawen's Blog

我喜欢这样自由的随手涂鸦, 因为我喜欢风......

1. 系统设置

1.1 在 /etc/ld.so.conf 中添加路径, 然后重新加载

include ld.so.conf.d/*.conf
/usr/local/lib64
/usr/local/lib
/usr/lib
/usr/lib64
/usr/local/boost/lib
ldconfig -v

1.2 环境变量中导出

# gcc找到头文件的路径
C_INCLUDE_PATH=$C_INCLUDE_PATH:/usr/local/boost/include
export C_INCLUDE_PATH

# g++找到头文件的路径
CPLUS_INCLUDE_PATH=$CPLUS_INCLUDE_PATH:/usr/local/boost/include
export CPLUS_INCLUDE_PATH

# 找到动态链接库的路径
LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/boost/lib
export LD_LIBRARY_PATH

# 找到静态库的路径
LIBRARY_PATH=$LIBRARY_PATH:/usr/local/boost/lib
export LIBRARY_PATH

如果是CMake, 还可以通过指令来引入: include_directories(path/to/include/dir)

1.3 GCC 7.1 编译安装

依赖的安装包有:

  • gmp-6.1.2
  • mpfr-3.1.5
  • mpc-1.0.3
wget http://ftp.gnu.org/gnu/gcc/gcc-7.3.0/gcc-7.3.0.tar.gz
tar -xvf gcc-7.3.0.tar.gz
cd gcc-7.3.0

# 下载依赖
./contrib/download_prerequisites

mkdir build;cd build
../configure --enable-checking=release --enable-languages=c,c++ --disable-multilib
# --disable-multilib: 用于关闭多个多个arch的库, 比如只需要64位的, 不需要32位的库, 那就添加这个配置
make -j 4

make install
cp /usr/local/lib64/libstdc++.so.6.0.24  /usr/lib64/

ln -sf /usr/lib64/libstdc++.so.6.0.24 /usr/lib64/libstdc++.so.6

# export LIBRARY_PATH=/lib64
# ./configure --prefix=/usr/local --enable-checking=release --enable-languages=c,c++ --disable-multilib
#  make
#  make install

2. gcc 编译

2.1 生成目标模块

gcc -c bill.c fred.c

# 直接使用目标模块: 
gcc -o program program.c bill.o fred.o  #或者源文件
gcc -o program program.c bill.c fred.c
# 都会带入不需要的模块

2.2 归档生成静态库文件

ar crv libfoo.a bill.o fred.o
ranlib libfoo.a

归档之后: 
gcc -o program program.c libfoo.a
或者: 
gcc -o program program.c -L. -lfoo
则会根据需要加载对应模块

2.3 在x64位Linux上生成动态链接库必须使用编译选项-fPIC的问题

2.3.1 在 Linux 下制作动态链接库, “标准” 的做法是编译成位置无关代码(Position Independent Code, PIC)

  • 通常的建议是始终加上-fPIC 生成位置无关代码;
  • AMD64 下, 必须使用位置无关代码, 否则连接失败: relocation R_X86_64_32S against `a local symbol' can not be used when making ashared object; recompile with -fPIC
  • IA32 下, 连接成功, 但有警告: warning: creating a DT_TEXTREL in object. 这样的 .so 文件可以完全正常工作。

2.3.2 PIC vs. relocatable

  • PIC 的缺点主要就是代码有可能长一些。例如 IA32, 由于不能直接使用[EIP+constant] 这样的寻址方式, 甚至不能直接将 EIP 的值交给其他寄存器, 要用到GOT(global offsettable)来定位全局变量和函数。这样导致代码的效率略低。
  • PIC 的加载速度稍快, 因为不需要做重定位。
  • 多个进程引用同一个 PIC 动态库时, 可以共用内存。这一个库在不同进程中的虚拟地址不同, 但操作系统显然会把它们映射到同一块物理内存上。对于可重定位代码, 则必须为每个库都在物理内存中复制一份副本, 因为需要修改其中的地址。当然, 主流现代操作系统都启用了分页内存机制, 这使得重定位时可以使用 COW(copy on write)来节省内存(32 位 Windows 就是这样做的); 然而, 页面的粒度还是比较大的(例如 IA32 上是 4KiB), 至少对于代码段来说能节省的相当有限。

3. Glibc 升级

wget https://mirrors.aliyun.com/gnu/glibc/glibc-2.31.tar.gz
tar -zxf glibc-2.31.tar.gz
cd glibc-2.31/
cat INSTALL | grep -E "newer|later"
The tests (and later installation) use some pre-existing files of the
   * GNU 'make' 4.0 or newer
   * GCC 6.2 or newer
     building the GNU C Library, as newer compilers usually produce
   * GNU 'binutils' 2.25 or later
   * GNU 'texinfo' 4.7 or later
   * GNU 'bison' 2.7 or later
   * GNU 'sed' 3.02 or newer
   * Python 3.4 or later
   * GDB 7.8 or later with support for Python 2.7/3.4 or later
   * GNU 'gettext' 0.10.36 or later

# 先升级对应的依赖包
yum install python3 binutils texinfo bison gettext

# 我的GDB 7.6.1 没升级, 依然ok

mkdir build
cd build
../configure --prefix=/usr --disable-profile --enable-add-ons --with-headers=/usr/include --with-binutils=/usr/bin --disable-sanity-checks --disable-werror
make -j6
make localedata/install-locales
make install

reboot

4. CMake

4.1 为单个目标生成编译数据库

cmake . -DCMAKE_EXPORT_COMPILE_COMMANDS=1 # 将产生以下 compile-commands.json

5. 问题辅助

5.1 常用工具

  • locate: 查看库依赖
  • lld: 列出动态依赖
  • nm:
    • 查看导出函数: nm -D **.so
  • strace: 对系统调用进行跟踪
  • objdump
    • 查看导出函数: objdump -tT **.so
  • ar : 创建和维护静态库
常用选项: 
r 替换归档文件中已有的文件或加入新文件
t 示归档文件的内容
d 从归档文件中删除文件
  • 生产内容表: ranlib
  • ldconfig: 解决共享库问题
  • objdumpreadelf

5.2 查看依赖库是否存在

locate libevent-2.1.so.6

结果: 系统已经安装了该模块, 在路径 /usr/local/lib/ 查看 memcached 查找依赖库的路径 LD_DEBUG=libs /usr/local/memcached/bin/memcached -v

5.3 踩过的坑

5.3.1 安装时出现: configure.ac:17: error: possibly undefined macro: AC_PROG_LIBTOOL

configure.ac:17: error: possibly undefined macro: AC_PROG_LIBTOOL
If this token and others are legitimate, please use m4_pattern_allow.
See the Autoconf documentation.
autoreconf: /usr/bin/autoconf failed with exit status: 1

出现之后那叫一个郁闷啊, 在网上搜索, 最终得到解决办法, 泪流满面啊·· 原来缺少一个工具: sudo apt-get install libtool

5.3.2 version `GLIBCXX_3.4.14' not found

两者是一个问题导致的: c++标准库太老了.没有更新。找到源码安装gcc的目录(gcc编译器最好还是源码安装: /usr/local/lib64/) 先find出libstdc++.so.6.0.22(我的是22) 如果不是源码安装就从根目录找:

find / -name "libstdc++.so*"

rm -rf libstdc++.so.6
ln -s libstdc++.so.6.0.22 libstdc++.so.6
ldconfig 
strings /usr/lib64/libstdc++.so.6 | grep GLIBC

5.3.3 collect2: 错误: ld 返回 1

gcc -static atexit.c -o atexit
/usr/bin/ld: cannot find -lc
collect2: 错误: ld 返回 1

解决方案: 需要安装glibc-static.xxx.rpm, 如glibc-static-2.12-1.107.el6_4.2.i686.rpm, 或是yum install glibc-static

5.3.4 Missing separate debuginfos, use: debuginfo-install glibc-2.17-106.el7_2.4.x86_64

需要先修改“/etc/yum.repos.d/CentOS-Debuginfo.repo”文件的enable=1;

yum install glibc glibc-debuginfo debuginfo-install glibc-2.17-106.el7_2.4.x86_64