28

I would like to offer a way that always builds my target as a 32-bit or always as 64-bit executable executable with cmake independent of the host system (Adding the "-m32" or "-m64" flag for gcc, not sure yet what to do for other compilers).

I can think of three ways to do this, which one should I use?

  1. an option (-DUSE32bit=true)
  2. a tool chain (-DCMAKE_TOOLCHAIN_FILE=64bit.toolchain)
  3. build types (-DCMAKE_BUILD_TYPE=release32)

In my case the forced 32-bit build will be the default and should be easy to use. A forced 64-bit build is the also useful for some cases and should not be too difficult. Using the bit width of the host system rarely makes sense for my case and I don't want to support it.

I found a related question here (The proper way of forcing a 32-bit compile using CMake) but the answers mostly discuss how it can be done at all, not how best to make it configurable.

Community
  • 1
  • 1
Flogo
  • 1,673
  • 4
  • 20
  • 33
  • For Visual Studio you can select it via setting the appropriate generator like e.g. [Visual Studio 12 2013 Win64 - Specify target platform x64](http://www.cmake.org/cmake/help/v3.3/generator/Visual%20Studio%2012%202013.html), the `cmake -A ` [command line option](http://www.cmake.org/cmake/help/v3.3/manual/cmake.1.html) or [CMAKE_GENERATOR_PLATFORM](http://www.cmake.org/cmake/help/v3.3/variable/CMAKE_GENERATOR_PLATFORM.html). – Florian Jul 01 '15 at 07:02
  • Thanks but this should work on Linux as well. – Flogo Jul 01 '15 at 09:31
  • Then there is a 4th variant: pre-loading the cache with something like `cmake -C 64bit.cmake ...`. I prefer this over the toolchain variant, if I'm not doing cross-compilation. A toolchain file normally influences the compiler detection itself. – Florian Jul 01 '15 at 11:56

4 Answers4

31

For Visual Studio and per https://cmake.org/cmake/help/latest/variable/CMAKE_GENERATOR_PLATFORM.html

For Visual Studio Generators with VS 2005 and above this specifies the target architecture.

cmake . -DCMAKE_GENERATOR_PLATFORM=x64
tresf
  • 7,103
  • 6
  • 40
  • 101
  • Thanks, this was what I was looking for! – blueether Jun 16 '18 at 21:54
  • 5
    @TylerGubala not yet, unfortunately. `cmake`'s docs lack an explation, but it appears the documentation for this is actually in the `-A` flag here: https://cmake.org/cmake/help/v3.2/manual/cmake.1.html, which says `VS>8`. See also https://stackoverflow.com/a/28047073/3196753 which talks about adding the `-m32` flag to `gcc`. Note, the `-m32` may not work for all compilers. The preferred and recommended way for 32-bit builds on Linux/Unix appears to be a Toolchain file, similar to how one would prepare a build environment for cross-compilation, also available in the link above. – tresf Jun 28 '18 at 18:50
  • @tresf Adding `-A Win32` works for me to force 32-bit compilation on a 64-bit Windows host. But is there a way to configure this in the toolchain file so that I don't have to pass in an additional command line argument? I already have separate toolchain files for Windows AMD64, Windows x86 and Linux AMD64. Eventually I'll need other Linux flavors as well, so I'd like a cross-platform way to do this. – Mitch Lindgren Jan 10 '20 at 01:24
  • 1
    @MitchLindgren CMake Toolchains are special because they're processed before anything else. For this reason, `SET(CMAKE_GENERATOR_PLATFORM x64)` (or in your case, `x86`) should do the trick in a Toolchain file. The `-D` parameter is simply setting this value on command line instead of from within the `MyToolChain.cmake`, `CMakeLists.txt`, etc. Disclaimer, I haven't tested this particular variable inside a toolchain file yet but the documentation does mention the Toolchain technique specifically. – tresf Jan 10 '20 at 05:02
  • 1
    Thanks, that worked. I had to use set the cache entry to internal (`set(CMAKE_GENERATOR_PLATFORM Win32 CACHE INTERNAL "Force 32-bit compilation")`) or it would get overwritten if not also specified on the command line, but once I did that it worked. – Mitch Lindgren Jan 11 '20 at 00:15
  • @MitchLindgren If your remove `CMakeCache.txt`, is the `CACHE` portion needed? You may not care to change it, as you've clearly observed it works more reliably when you have control over the cached value, but to be as technically correct as possible, I'd expect the `SET(...)` to work first try per the documentation.... granted this does assume you've deleted that file or that `cmake` not been called yet. I ask because many values get cached and you may choose to take the undesired cache behavior as a warning sign that you've begun building with the wrong toolchain resulting in other issues. – tresf Jan 11 '20 at 04:04
  • 2
    @tresf yes, I do need the `CACHE` portion even if I delete `CMakeCache.txt` first. Otherwise, when I try to build, I get this error: `error MSB8013: This project doesn't contain the Configuration and Platform combination of Debug|x64` – Mitch Lindgren Jan 13 '20 at 22:16
  • 1
    @MitchLindgren Hmm... interesting. That suggests one of the following: 1. There's a bug with `cmake` as the documentation provided this as a viable method. -- OR -- 2. Removing `CMakeCache.txt` isn't enough to reset the value of this variable so the value ultimately needs to be set from a fresh build (blow away all cached build files). Regardless, your testing and replies will help others. Thanks for testing! – tresf Jan 14 '20 at 18:31
9

TL;DR

Use toolchain

In depth

  1. an option (-DUSE32bit=true)

This is not scalable I guess. So what if you want to build N projects? You have to add N options.

  1. build types (-DCMAKE_BUILD_TYPE=release32)

This may work well. But in my opinion you're mixing unrelated stuff. Also I'm sure you have to adapt find_package behaviour by setting some *_ROOT CMake variables. It's not possible to do it with CMAKE_BUILD_TYPE (at least, again, in a scalable fashion).

  1. a tool chain (-DCMAKE_TOOLCHAIN_FILE=64bit.toolchain)

The best variant. If you want to build two projects - just use same toolchain:

cmake -Hproj-1 -B_builds/proj-1 -DCMAKE_TOOLCHAIN_FILE=/.../64bit.toolchain
cmake -Hproj-2 -B_builds/proj-2 -DCMAKE_TOOLCHAIN_FILE=/.../64bit.toolchain

If you want to build your 3rd party ExternalProject_Add with 64 bit architecture - just pass toolchain to CMAKE_ARGS:

ExternalProject_Add(
    ...
    CMAKE_ARGS ... -DCMAKE_TOOLCHAIN_FILE=/.../64bit.toolchain
    ...
)

Want to adapt find_package - just add any CMake variables to toolchain file.

  • 1
    Thanks. I only have one project and no third-party libraries that I build myself. I would prefer to keep the call to be a bit simpler, i.e., when called without parameters, cmake should generate the 32-bit version. Can I default to the 32-bit tool chain or is this bad style? – Flogo Jul 01 '15 at 09:30
  • 1
    @Flogo Everything that you call with `-D` is put in the cache. You can make use of the fact that cache variables are not overwritten when set again (CMake itself uses this behavior for some of its system variables). So if you put e.g. a `set(CMAKE_TOOLCHAIN_FILE ... CACHE INTERNAL "")` before your `project()` command it will be the default. – Florian Jul 01 '15 at 11:30
  • @Flogo But it could be difficult to select the right default toolchain. You would have to make it dependent on the [CMAKE_GENERATOR](http://www.cmake.org/cmake/help/v3.0/variable/CMAKE_GENERATOR.html) used. – Florian Jul 01 '15 at 12:20
  • @ruslo I specifically wan to avoid the default behavior because a 64-bit build only makes sense in very few special cases for my application. I am now leaning towards a different approach: I will not force anything in cmake but will check whether CMAKE_SIZEOF_VOID_P is 4. If it isn't, I will check if an option that defaults to false was set to true. If that option is also not set, I will stop with an error explaining the situation. This way, everyone can chose their own setup, but 64-bit builds have to be explicitly confirmed. What do you think? – Flogo Jul 03 '15 at 09:00
1

Personally I wanted to switch to 32/64-bit projects within same solution for Visual studio / cmake configuration. I've figured out that this can be done using

set_target_properties(${project} PROPERTIES LINK_FLAGS ${PROJ_LINK_FLAGS})

where PROJ_LINK_FLAGS can be either /MACHINE:X86 or /MACHINE:X64 depending on compilation.

TarmoPikaro
  • 4,723
  • 2
  • 50
  • 62
1

thanks for all your inputs, but on my side i've finally chosen the -m32 hack with cmake

# cmake windows 32 bits mode bug: 32 bits link mode must be explicit (otherwise cmake will always guess a 64 bits target)
#  1- run "vcbarsall.bat x86" to setup Visual Studio build profile
#  2- "set cflags=-m32" and "set cxxflags=-m32"
#  3- let the cmake plugin "automatically" guess the target platform