1

cmake compiles first the .c files to .o files, and then links them together:

gcc a.c -o a.c.o
gcc b.c -o b.c.o
gcc c.c -o c.c.o
gcc a.c.o b.c.o c.c.o -o a.out

That instead of compiling directly from source files to binary:

gcc a.c b.c c.c -o a.out

Normally I would have used link-time-optimization (-flto) to allow the compiler to do cross-binary optimization, but unfortunately, I have to use an old compiler that doesn't support link-time-optimization.

That means, that if I use cmake, my binary comes out 3 times larger than if I compile directly from source files to binary, because of the lack of cross-binary optimization

Do you know a way to make cmake compile directly from source files to binary, or do you know an alternative way to solve this?

sepp2k
  • 363,768
  • 54
  • 674
  • 675

2 Answers2

0

use a custom command or target and use the COMMAND param to build your source files.

Joel
  • 1,805
  • 1
  • 22
  • 22
0

From my experience if you have problems like the binary being 3 times larger when utilizing CMake you need to look at the complete build process.

First check if the compiler/linker options are really same: Using CMake with GNU Make: How can I see the exact commands?

If they all match you can - to find out what sections are actually larger - compare the map files of your output in the CMake and non-CMake case. In CMake you need to add -Wl,-Map=<TARGET_NAME>.map to your linker flags. How to add linker flags see: CMake: How to set the LDFLAGS in CMakeLists.txt?

Or alternatively use nm or size on your a.out: Tool to analyze size of ELF sections and symbol

Last you try activating other optimization options of your linker (the generic -O option should be supported even by older compilers). See also: Remove useless files, includes, global variables and functions in C++

.c vs .o and GNU on Windows

There should not be a difference between giving the source files or the object files to gcc. But if you're using the GNU toolchain on Windows you may have been stumbled across a workaround in Windows-GNU.cmake:

# The gcc/collect2/ld toolchain does not use response files
# internally so we cannot pass long object lists.  Instead pass
# the object file list in a response file to the archiver to put
# them in a temporary archive.  Hand the archive to the linker.

This workaround does result in:

gcc a.c -o a.c.o
gcc b.c -o b.c.o
gcc c.c -o c.c.o
rm objects.a
ar cr a.c.o b.c.o c.c.o -o objects.a
gcc objects.a -o a.out

The problem is the ar call in the middle. If CMake would take the .o files directly you would be fine.

You can overwrite this workaround by setting CMAKE_C_LINK_EXECUTABLE back to its default after your project() command:

set(CMAKE_C_LINK_EXECUTABLE "<CMAKE_C_COMPILER> <FLAGS> <CMAKE_C_LINK_FLAGS> <LINK_FLAGS> <OBJECTS>  -o <TARGET> <LINK_LIBRARIES>")

Additional reference: CMake: use a custom linker

Community
  • 1
  • 1
Florian
  • 39,996
  • 9
  • 133
  • 149