64

Sorry that there are many similar questions, but I do find that Googling for CMake queries always yields similar-but-not-the-same scenarios, conflicting CMake commands and so on!

I need to force my project to build 32-bit binaries because I have to link with a library which is only available as 32-bit. I diagnosed this based on error messages such as:

/usr/bin/ld: i386 architecture of input file `*external-32bit-lib*' is incompatible with i386:x86-64 output

From what I gather, I should therefore use:

set (CMAKE_CXX_FLAGS "-m32")

This does change things - I now get several errors like:

/usr/bin/ld: i386 architecture of input file `*project-output-lib*' is incompatible with i386:x86-64 output

AND still get the same errors for the external library too. I think this is because the -m32 made gcc generate 32-bit binaries, but ld is still trying for 64-bit output? Further Googling for this problem didn't give any success, so if anyone could verify that I am right and give the correct way of doing this, I would be very grateful!

Many thanks!

devrobf
  • 6,973
  • 2
  • 32
  • 46

6 Answers6

52

If you want to compile and link for 32 bit using cmake use this for creating libraries and binaries:

Creating libraries:

add_library(mylib SHARED my_source.c)
set_target_properties(mylib PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")

creating executables:

add_executable(mybin sources.c)
set_target_properties(mybin PROPERTIES COMPILE_FLAGS "-m32" LINK_FLAGS "-m32")
Micha Wiedenmann
  • 19,979
  • 21
  • 92
  • 137
ant2009
  • 27,094
  • 154
  • 411
  • 609
26

Even if this seems like extra works, I believe a proper solution is to use toolchain file in this case. Something like:

# the name of the target operating system
set(CMAKE_SYSTEM_NAME Linux)

# which compilers to use for C and C++
set(CMAKE_C_COMPILER gcc)
set(CMAKE_C_FLAGS -m32)
set(CMAKE_CXX_COMPILER g++)
set(CMAKE_CXX_FLAGS -m32)

# here is the target environment located
set(CMAKE_FIND_ROOT_PATH   /usr/i486-linux-gnu )

# adjust the default behaviour of the FIND_XXX() commands:
# search headers and libraries in the target environment, search
# programs in the host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)

Then usage is simply:

$ cmake -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake /path/to/source

The important part here is that one is now able to specify a root dir path (CMAKE_FIND_ROOT_PATH) which should be used to search for third party lib. Indeed your compiler may not be smart enough to know where to search for an x86 Qt library on an x86_64 system.

Having a toolchain file allows one to specify a different one on a par compiler basis, and you should be able to tweak the option when compiling in 32bits from a windows environement.

Nowadays this is extra works since compiling 32bits from an x86_64 Linux OS is pretty much trivial, but this solution will work for other more exotic setup.

For more information on toolchain file, one can check for example:

Ray Depew
  • 573
  • 1
  • 9
  • 22
malat
  • 12,152
  • 13
  • 89
  • 158
  • 11
    A toolchain file may be a bit much when `cmake /path/to/source -DCMAKE_CXX_FLAGS=-m32 -DCMAKE_C_FLAGS=-m32` might do, but these two are the only proper ways of handling this situation. CMakeLists.txt should not contain this kind of "information". Unless the OP wants to prevent a 64-bit compile from ever happening. – rubenvb Jan 20 '15 at 13:57
  • @rubenvb as explained in my post, you still need `CMAKE_FIND_ROOT_PATH` to help cmake handle something like `find_package(Qt)` – malat Jan 20 '15 at 13:59
  • using this technique and cmake 3.9.3 , CMAKE_CXX_FLAGS defined in toolchain was NOT propagated in child projects the first time I am creating the build directory. But the behaviour changes if you run a second time the command to create the build directory without deleting the existing build directory !!! I don't exactly know if this is a normal feature or not ... To solve the problem , I defined CMAKE_CXX_FLAGS as follow in toolchain file : `set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -m32" CACHE STRING "c++ flags")` – sancelot Nov 06 '17 at 11:09
  • 1
    What sould you recommand to easily switch compiling 32 / 64 ? (without file edition, I mean) – Sandburg Nov 29 '19 at 16:40
11

CMAKE_CXX_FLAGS only affects the C++ compiler. You probably also have to set the flag for the C compiler:

set (CMAKE_C_FLAGS "-m32")
sakra
  • 62,199
  • 16
  • 168
  • 151
4

It sounds like you did not pass m32 to LFLAGS too, or there are old obj files skulking about. Be sure to clean first.

This question is similar to yours: cmake, gcc, cuda and -m32

Community
  • 1
  • 1
Fredrik E
  • 1,840
  • 13
  • 18
  • Thanks -that may well be the case - but how would I do that though CMake? And is this the most sensible or 'proper' way to do it? I did clean btw :) – devrobf Apr 27 '11 at 14:45
  • Updated answer. See link. I meant clean your hands, you're dirty :) – Fredrik E Apr 27 '11 at 14:51
  • Cheers, but unfortunately the link doesn't seem to help. Setting LDFLAGS seems to have no effect... – devrobf Apr 27 '11 at 15:05
3

Use TRY_RUN command by the following source.

size.cpp:

#include <cstdlib>

int main( int argc, char** argv )
{
  size_t size = sizeof(void*);
  if ( size == 4 )
    return 0;
  return 1;
}

CMakeLists.txt:

TRY_RUN(RUN_RESULT_VAR COMPILE_RESULT_VAR ${your_temp_dir} size.cpp RUN_OUTPUT_VARIABLE IS_64_SYSTEM)
IF(IS_64_SYSTEM)
  MESSAGE(FATAL_ERROR "64 compiling not allowed!")
ENDIF(IS_64_SYSTEM)

It will work on all standard compiler.

Naszta
  • 7,560
  • 2
  • 33
  • 49
2

I used malat's approach and made a Toolchain file.

I have a Toolchain file that works on some Linux dists, perhaps it will give you inspiration. It may work for you as is, or you may need other ugly hacks to get other cmake scripts you rely on to work or w/e:

https://github.com/visualboyadvance-m/visualboyadvance-m/blob/master/cmake/Toolchain-cross-m32.cmake

josliber
  • 43,891
  • 12
  • 98
  • 133
Rafael Kitover
  • 967
  • 10
  • 13