MantisBT - CMake
View Issue Details
0015223CMakeCMakepublic2014-10-28 12:072015-04-06 09:07
Emmanuel Blot 
 
normalmajoralways
closedno change required 
Any
CMake 3.0 
 
0015223: Object OUTPUT_EXTENSIONs selection is hard - if ever possible - to manage with cross compilation
For some (historical?) reasons, CMake considers the default object extension tas ".obj", which is quite unusual but on Windows.

CMake "Modules" files define:
IF (UNIX)
 set(CMAKE_<LANG>_OUTPUT_EXTENSION .o)
ELSE ()
 set(CMAKE_<LANG>_OUTPUT_EXTENSION .obj)
ENDIF ()

which makes the Unix style the exception, and Windows style the default rule.

However, when cmake is used to cross compile, many (if not most) OSes use the Unix style, even if they are not Unix-based.

The trouble is that UNIX variable seems to be mostly defined from the host environment, not from the target environment.

The net result is that ".obj" extension is enforced for non-Windows targets, which in turn rapidly becomes a nightmare to manage.

Forcing UNIX to 1 from a CMakeLists.txt sometimes helps for C source files - although it is definitely a hack - but does not with ASM files for example.

Setting CMAKE_<LANG>_OUTPUT_EXTENSION from a CMakeLists.txt does not seem to be recommended - from previous CMake ML posts - and does not work anyway.

Although I would personally favour .o to be the default extension and Windows the exception, I guess that for at least compatibility with previous CMake version this cannot be changed.

However, being able to easily define the extension for a non Unix project, or for a cross compiled one is definitely a real need.

I've failed - up to know - to find a way to choose the proper extension, which forced me to write ugly workaround in CMakeLists.txt files.
No tags attached.
Issue History
2014-10-28 12:07Emmanuel BlotNew Issue
2014-10-28 12:34Brad KingNote Added: 0037085
2014-10-31 09:16Emmanuel BlotNote Added: 0037112
2014-10-31 09:38Brad KingNote Added: 0037113
2014-10-31 09:38Brad KingNote Edited: 0037113bug_revision_view_page.php?bugnote_id=37113#r1605
2014-10-31 10:45Emmanuel BlotNote Added: 0037116
2014-10-31 10:46Emmanuel BlotNote Edited: 0037116bug_revision_view_page.php?bugnote_id=37116#r1607
2014-10-31 10:52Brad KingNote Edited: 0037116bug_revision_view_page.php?bugnote_id=37116#r1608
2014-10-31 11:02Brad KingNote Added: 0037117
2014-10-31 12:48Emmanuel BlotNote Added: 0037121
2014-10-31 12:56Brad KingStatusnew => resolved
2014-10-31 12:56Brad KingResolutionopen => no change required
2015-04-06 09:07Robert MaynardNote Added: 0038436
2015-04-06 09:07Robert MaynardStatusresolved => closed

Notes
(0037085)
Brad King   
2014-10-28 12:34   
CMake is widely used for cross-compiling with many toolchains. Please provide a specific and complete example of what you're doing and what goes wrong: source tree, command lines used, etc.
(0037112)
Emmanuel Blot   
2014-10-31 09:16   
While trying to find the smallest possible example, I found the root cause of the issue:

  PROJECT (demo)
  SET (CMAKE_SYSTEM_NAME Generic)

outputs '.o' files, while

  SET (CMAKE_SYSTEM_NAME Generic)
  PROJECT (demo)

outputs '.obj' files! (the initial issue)

with the following CMakeLists.txt file:

  CMAKE_MINIMUM_REQUIRED (VERSION 3.0.0)
  INCLUDE (CMakeForceCompiler)
  FIND_PROGRAM (xcc arm-eabi-gcc)
  CMAKE_FORCE_C_COMPILER (${xcc} GNU)
  CMAKE_FORCE_CXX_COMPILER (${xcc} GNU)
  PROJECT (demo)
  SET (CMAKE_SYSTEM_NAME Generic)
  ENABLE_LANGUAGE (ASM)
  ADD_LIBRARY(demolib
              asm.S
              cc.c)

While PROJECT and ENABLE_LANGUAGE order is well documented, I did not noticed that SET(CMAKE_SYSTEM_NAME ...) should have been used **after** the PROJECT command

Maybe that some other commands ordering are wrong in my CMake scripts. It is not the first time I fail to find/guess the proper order of commands, or more explicitly which commands apply to whatever context.
(0037113)
Brad King   
2014-10-31 09:38   
Re 0015223:0037112: Actually CMAKE_SYSTEM_NAME should be set before the project command. Typically it is done in a toolchain file specified with CMAKE_TOOLCHAIN_FILE. The first project or enable_language command loads the toolchain file as part of initializing the target platform information. See:

 http://www.cmake.org/cmake/help/v3.1/manual/cmake-toolchains.7.html#cross-compiling [^]
 http://www.cmake.org/Wiki/CMake_Cross_Compiling [^]

The CMAKE_SYSTEM_NAME contributes to which compiler/platform information files get loaded from the language init modules:

 http://www.cmake.org/gitweb?p=cmake.git;a=blob;f=Modules/CMakeCInformation.cmake;hb=v3.0.2#l15 [^]

Since you're setting it to "Generic" CMake does not load any of the unix information so nothing sets "UNIX" to 1. Therefore the default object extension is ".obj". If you also add

 set(UNIX 1)

to your toolchain file then you will get ".o".

(0037116)
Emmanuel Blot   
2014-10-31 10:45   
(edited on: 2014-10-31 10:52)
So actually, the ordering is really hard to understand/solve:

# First case
PROJECT (demo)
ENABLE_LANGUAGE (ASM)
SET (CMAKE_SYSTEM_NAME Generic)

-> Generates .o files, but use the wrong archiver, i.e. /usr/bin/ar instead of arm-eabi-ar to archive the library files

# Second case
ENABLE_LANGUAGE (ASM)
PROJECT (demo)
SET (CMAKE_SYSTEM_NAME Generic)

-> Generate .o files, use the proper archive, but contradicts the CMake documentation that states that ENABLE_LANGUAGE should be set after PROJECT statement

# Third case
SET (CMAKE_SYSTEM_NAME Generic)
PROJECT (demo)
ENABLE_LANGUAGE (ASM)

--> Generate .obj files, use the proper archiver.

Adding SET (UNIX 1) before PROJECT -or- after ENABLE_LANGUAGE does not help with this issue, but:

# Forth case
SET (CMAKE_SYSTEM_NAME Generic)
PROJECT (demo)
SET (UNIX 1)
ENABLE_LANGUAGE (ASM)

--> Generate .o for .S file, .obj for .c file, use the proper archiver.

# Fifth case
SET (CMAKE_SYSTEM_NAME Generic)
ENABLE_LANGUAGE (ASM)
SET (UNIX 1)
PROJECT (demo)

--> Generate .obj for S file, .o for .c file!, use the proper archiver.

So it seems the only working combination is (2), but contradict both the documentation and your previous comment, so I guess it works but should not.

At this point, I am totally lost on the proper sequence to use

(0037117)
Brad King   
2014-10-31 11:02   
Re 0015223:0037116: Everything about the choice of target system should be set before enable_language or project. By setting the information later than that you are actually configuring with information about the host platform. It appears to work because you happen to be using unix host.

Try this:

$ cat Platform/MySystem.cmake
include(Platform/Generic)
set(UNIX 1)
$ cat CMakeLists.txt
cmake_minimum_required (VERSION 2.8.12)
list (APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_SOURCE_DIR})
set (CMAKE_SYSTEM_NAME MySystem)
project (demo C ASM)
...
(0037121)
Emmanuel Blot   
2014-10-31 12:48   
Works perfectly. Thanks **a lot**
I think the ticket can be closed.
(0038436)
Robert Maynard   
2015-04-06 09:07   
Closing resolved issues that have not been updated in more than 4 months.