CMake创建并链接32位和64位版本的库

时间:2018-08-01 16:15:11

标签: cmake 32bit-64bit

我尝试两次编译以下代码,一次使用function hex2str($string) { return preg_replace_callback( '/(\\\\x[a-f\d]{2})+/i', function ($matches) { return stripcslashes($matches[0]); }, $string ); } ,一次不使用:

-m32

我的CMakeLists.txt中包含以下内容:

// File mylib.cc

#include <iostream>

void print_int_size() {
  std::cout << sizeof(int*) << std::endl;
}


// File main.cc

void print_int_size();

int main() {
  print_int_size();
  return 0;
}

编译时会得到以下输出(类似于gcc):

project (Link32b VERSION 0.91 LANGUAGES CXX)


add_library ( mylib STATIC mylib.cc )
add_library ( mylib_32b STATIC mylib.cc )

target_compile_options ( mylib_32b PUBLIC -m32 )

add_executable ( main main.cc )
add_executable ( main_32b main.cc )

target_compile_options ( main_32b PRIVATE -m32 )

target_link_libraries ( main PRIVATE mylib )
target_link_libraries ( main_32b PRIVATE mylib_32b )

我在这里想念什么?

===

更新:很好奇,将Scanning dependencies of target mylib [ 12%] Building CXX object CMakeFiles/mylib.dir/mylib.cc.o [ 25%] Linking CXX static library libmylib.a [ 25%] Built target mylib Scanning dependencies of target main [ 37%] Building CXX object CMakeFiles/main.dir/main.cc.o [ 50%] Linking CXX executable main [ 50%] Built target main Scanning dependencies of target mylib_32b [ 62%] Building CXX object CMakeFiles/mylib_32b.dir/mylib.cc.o [ 75%] Linking CXX static library libmylib_32b.a [ 75%] Built target mylib_32b Scanning dependencies of target main_32b [ 87%] Building CXX object CMakeFiles/main_32b.dir/main.cc.o [100%] Linking CXX executable main_32b ld: warning: ignoring file CMakeFiles/main_32b.dir/main.cc.o, file was built for i386 which is not the architecture being linked (x86_64): CMakeFiles/main_32b.dir/main.cc.o ld: warning: ignoring file libmylib_32b.a, file was built for archive which is not the architecture being linked (x86_64): libmylib_32b.a Undefined symbols for architecture x86_64: "_main", referenced from: implicit entry/start for main executable ld: symbol(s) not found for architecture x86_64 clang: error: linker command failed with exit code 1 (use -v to see invocation) make[2]: *** [main_32b] Error 1 make[1]: *** [CMakeFiles/main_32b.dir/all] Error 2 make: *** [all] Error 2 设置为包含CMAKE_CXX_FLAGS可以使示例工作。但是,我希望在不设置变量的情况下完成此操作,即遵循基于现代目标的方法。

3 个答案:

答案 0 :(得分:0)

为简化项目的维护,建议您使构建系统尽可能简单,而应配置和构建项目 两次:

  • 一个用于64位二进制文​​件的版本
  • 一个用于32位二进制文​​件的版本:

    • 通过将CXXFLAGSCFLAGS环境变量设置为-m32(方法1)
    • 或通过设置三个环境变量ASCXXCC(方法2)

简化您的示例项目

还请确保添加cmake_minimum_required,否则将收到错误VERSION not allowed unless CMP0048 is set to NEW

cmake_minimum_required(VERSION 3.10)
project (Link VERSION 0.91 LANGUAGES CXX)
add_library ( mylib STATIC mylib.cc )
add_executable ( main main.cc )
target_link_libraries ( main PRIVATE mylib )

通过使用一个更简单的构建系统,该构建系统不对有关工具链的假设进行硬编码,因此可以隐式地启用对跨平台和不同环境(如ARM等)的支持,这也可以使持续集成变得更加容易。例如,在CircleCI上,您将有两个构建作业(一个用于64位,一个用于32位)均构建一个简单项目。

安装必需的i386库

在Ubuntu上,可以这样做

sudo apt-get install \
  gcc-multilib \
  g++-multilib \
  libc6:i386 \
  libstdc++6:i386

其他依赖项将使用packageName:i386

安装

分步:方法1

假设我们具有以下目录结构:

<root>
  |
  |-src
  |  |--- CMakeLists.txt
  |  |--- main.cc
  |  |--- mylib.cc
  |
  |-build
  |   |-- ...
  |
  |-build-32
      |-- ...

您只需执行以下操作即可编译32位版本:

CFLAGS=-m32 CXXFLAGS=-m32 cmake -Hsrc -Bbuild-32

分步:方法2

方法2的目标是引入交叉编译的思想。

在上一节中,您将了解内部应用相同原理的dockcross/linux-32码头工人镜像。

asgccg++创建三个包装器脚本

以下是三个shell脚本的内容:

  • i686-linux-gnu-as

#!/bin/bash exec as -m32 "$@"

  • i686-linux-gnu-gcc

#!/bin/bash exec gcc -m32 "$@"

  • i686-linux-gnu-g ++

#!/bin/bash exec g++ -m32 "$@"

编译

假设我们具有以下目录结构:

<root>
  |-bin
  |  |- i686-linux-gnu-as
  |  |- i686-linux-gnu-g++
  |  |- i686-linux-gnu-gcc
  |
  |-src
  |  |--- CMakeLists.txt
  |  |--- main.cc
  |  |--- mylib.cc
  |
  |-build
  |   |-- ...
  |
  |-build-32
      |-- ...

您将分别做

64位
$ cmake -Hsrc -Bbuild; cmake --build ./build
-- The CXX compiler identification is GNU 5.2.1
-- Check for working CXX compiler: /usr/bin/c++
-- Check for working CXX compiler: /usr/bin/c++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /tmp/scratch/build
[...]
[100%] Built target main

$ file ./build/main 
./build/main: ELF 64-bit LSB executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=e28e610f85cd4a2ab29e38ed58c1cb928f4aaf33, not stripped

$ ./build/main 
4
32位
$ CXX=$(pwd)/bin/i686-linux-gnu-g++ \
  CC=$(pwd)/bin/i686-linux-gnu-gcc \
  AS=$(pwd)/bin/i686-linux-gnu-as linux32 \
  bash -c "cmake -Hsrc -Bbuild-32; cmake --build ./build-32/"
-- The CXX compiler identification is GNU 5.2.1
-- Check for working CXX compiler: /tmp/scratch/bin/i686-linux-gnu-g++
-- Check for working CXX compiler: /tmp/scratch/bin/i686-linux-gnu-g++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
[...]
[100%] Built target main

$ file ./build-32/main 
./build-32/main: ELF 32-bit LSB executable, Intel 80386, version 1 (SYSV), dynamically linked, interpreter /lib/ld-linux.so.2, for GNU/Linux 2.6.32, BuildID[sha1]=b7f5781f66a28e28d28eda2b798b671c1e89e22a, not stripped

$ ./build-32/main 
4

现在要了解为什么sizeof(int)在64位和32位版本上都相同,请考虑阅读C/C++: sizeof(short), sizeof(int), sizeof(long), sizeof(long long), etc... on a 32-bit machine versus on a 64-bit machine

使用dockcross简化编译

现在,要轻松编译为32位,您还可以使用对接图像dockcross/linux-x86。参见https://github.com/dockcross/dockcross#readme

docker pull dockcross/linux-x86
docker run -ti --rm dockcross/linux-x86 > dockcross-linux-x86
chmod u+x dockcross-linux-x86

然后进行编译,您将这样做:

dockcross-linux-x86  bash -c "cmake -Hsrc -Bbuild-32; cmake --build ./build-32/"

答案 1 :(得分:0)

出于链接目的,未“继承” -m32标志:

target_compile_options ( <lib> PUBLIC -m32 )
target_link_libraries ( <target> PRIVATE <lib> ) // Does not link with `-m32`.

请注意,由于{{1}的<target>是“继承” -m32的编译选项,因此上述内容导致target_link_librariesPUBLIC编译 }}。但是,该标志 not 不会传递给链接器。

此外,没有<lib>命令,因此无法插入行target_link_options来解决问题。

相反,对于this answer(略有修改),正确的方法是

target_link_options ( <link> PUBLIC -m32 )

答案 2 :(得分:0)

OP's answer的附加内容:Cmake 3.13+ has target_link_options命令,因此您可以编写: target_link_options(<target> PRIVATE "-m32")