【问题标题】:CMake create and link 32bit and 64bit versions of libraryCMake 创建和链接 32 位和 64 位版本的库
【发布时间】:2019-01-09 07:13:49
【问题描述】:

我试图编译以下代码两次,一次使用-m32,一次没有:

// 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;
}

我的 CMakeLists.txt 中有以下内容:

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 )

编译时得到如下输出(与gcc类似):

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 设置为包含-m32 会使示例工作。但是,我想在不设置变量的情况下完成它,即遵循现代基于目标的方法。

【问题讨论】:

  • 看起来您还需要为 链接器 指定标志 -m32,例如在 that answer 中。请注意,STATIC 库不需要链接器标志,因为它实际上没有链接。
  • 似乎答案是-m32 选项不是INTERFACEd 输出到链接器。这解决了我的问题;如果您添加回复,我很乐意接受。
  • 确实可以从this reply 推断出我的问题的答案,但是(a)该线程上的前几个答案根本不是我想要的,并且(b)问题本身是不同的.该用户询问如何使用-m32 编译他们自己的代码,而我询问如何将-m32 标志传递给链接器。我的问题的另一个组成部分是,假设 -m32 选项将可供链接器使用似乎是合理的,因为它是链接库的 PUBLIC 属性,但显然情况并非如此。跨度>
  • “该线程上的前几个答案根本不是我想要的” - 呃?第一个答案告诉使用 LINK_FLAGS。至于设置 COMPILE_FLAGS 属性 - 它与target_compile_options 相同。 “该用户询问如何使用-m32 编译他们自己的代码,而我询问如何将-m32 标志传递给链接器。” - 你的整个问题是用-m32 编译,而引用的问题正是关于这个问题的。当然,并非所有答案都适合您,但您想要的答案都包含在所引用的问题中。

标签: cmake 32bit-64bit


【解决方案1】:

除了OP's answer: Cmake 3.13+ has target_link_options 命令因此你可以写: target_link_options(&lt;target&gt; PRIVATE "-m32")

【讨论】:

    【解决方案2】:

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

    • 为 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 docker 镜像在内部应用了相同的原理。

    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 映像 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/"
    

    【讨论】:

    • 我是 2 diff 构建理念的专家,但不足以在每个案例上修改 CMAKE_&lt;LANGUAGE&gt;_FLAGS(通过添加或不添加 -m32)? (我不是指multilib 安装,这是必要的)。
    • 建议不要修改CMAKE_*FLAGS变量,而是建议在配置前设置环境变量CXXFLAGSCFLAGS。这将确保 CMAKE_*FLAGS 按预期初始化:CFLAGS=-m32 CXXFLAGS=-m32 cmake -Hsrc -Bbuild-32
    • 对不起,我很困惑;你的答案在哪里发生?我找不到CXXFLAGS 的设置。您只需围绕各种工具创建包装脚本,不是吗?换句话说,是否有必要大惊小怪地创建包装器?即使在@Tsyvarev 链接的答案中,也使用了CMAKE_&lt;LANGUAGE&gt;_FLAGS 和朋友。这不是最灵活的方法,也符合现代 cmake 实践吗?
    • 这可以完成工作,但这不是我想要的。回答我的问题是没有类似于target_compile_optionstarget_link_options,因此需要使用set_target_properties 设置LINK_FLAGS 属性。我想避免让用户指导编译。
    • 此外,sizeof(int) 是一个错误,我打算改用sizeof(int*)。我已经相应地编辑了我的问题。
    【解决方案3】:

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

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

    请注意,由于target_link_libraries“继承”PUBLIC 来自&lt;lib&gt; 的编译选项,上述原因导致&lt;target&gt;-m32 一起编译。但是,该标志没有传递给链接器。

    而且,没有target_link_options命令,所以不能插入target_link_options ( &lt;link&gt; PUBLIC -m32 )这一行来解决问题。

    相反,根据this answer(稍作修改),正确的方法是

    target_compile_options ( <lib> PUBLIC -m32 )
    set_target_properties ( <target> PROPERTIES LINK_FLAGS -m32 )
    target_link_libraries ( <target> PRIVATE <lib> )
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-03-17
      • 2015-04-30
      • 1970-01-01
      • 2019-07-06
      • 2016-12-25
      • 1970-01-01
      • 2010-12-03
      相关资源
      最近更新 更多