15

I'm building an executable using the standard command:

add_executable(MyExe a.c b.c)

I'm adjusting the CMAKE_EXE_LINKER_FLAGS to emit a map file, and it works.

If I delete the map file, though, performing an incremental build doesn't regenerate the map file. This makes sense, since I haven't expressed to cmake that the map file depends on MyExe. In the above scenario, the MyExe.map isn't even a target, so cmake doesn't even know it exists.

I've tried creating a custom target, but I can't create a custom command that regenerates the map file, since it comes from add_executable(). I then tried to use add_dependencies(), but that seems to only influence the build order.

I could explicitly re-run the linker as a custom command that builds a custom target, but that seems wasteful since linking does take a bit of time.

It almost seems like I need some way to tell add_executable that there are more outputs than just the executable image. Is there a way to do this?

If anybody could point me in the right direction, I'd appreciate it! Thanks in advance for reading.

sergej
  • 17,147
  • 6
  • 52
  • 89
Charles Nicholson
  • 888
  • 1
  • 8
  • 21
  • Man, this is the same problem I'm having. Are you working on Solaris? – jww Aug 27 '17 at 02:56
  • 1
    "I'm adjusting the CMAKE_EXE_LINKER_FLAGS to emit a map file" - please show the code for this. How long does linking take? Are you using the Gold linker? If not, it is much faster. – John Zwinck Aug 27 '17 at 03:00
  • @jww Are you looking for a cross-platform way to generate Mapfiles with CMake and then use that as an input for a custom command? Maybe I just got it wrong, but your problem sounds different from the one described in the question. – Florian Aug 27 '17 at 20:24
  • Well, we don't distribute a mapfile. Rather, we build it on the fly when needed and write it to disk (in the GNU makefile). So we would like to generate the map file and make the program (*.exe) and shared object (*.so) a dependency of the mapfile. – jww Aug 27 '17 at 20:34
  • @jww Added an alternative to my answer that also covers your use case (for makefile generators). – Florian Aug 30 '17 at 20:36

1 Answers1

13

I've seen the same question was also asked on CMake's mailing list and never received an answer. So let me try to answer it here.

CMake doesn't have an official support for map files nor - if you add the necessary linker flags manually - to have more then one output of an executable target.

If you don't want to add it as an extra custom command/target step, you could link to an object file being part of you executable with OBJECT_OUTPUTS source file property (works unfortunately only with Makefile generators).

I've successfully tested the following example with a GNU toolchain:

cmake_minimum_required(VERSION 2.6)

project(MapFileDep)

file(WRITE "main.cpp" "int main() { return 0; }")

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set(
        CMAKE_EXE_LINKER_FLAGS 
        "${CMAKE_EXE_LINKER_FLAGS} -Wl,-Map=output.map"
    )
endif()

add_executable(${PROJECT_NAME} "main.cpp")

if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
    set_source_files_properties(
        "main.cpp" 
        PROPERTIES OBJECT_OUTPUTS "output.map"
    )
endif()

Alternative

And here the more advanced alternative (also covering @jww's use case):

Add something that generates/creates/copies the output.map file (when it's not there) and use LINK_DEPENDS target property to make CMake aware of re-linking when output.map changes:

add_custom_command(
    OUTPUT "output.map"
    COMMAND "${CMAKE_COMMAND}" -E touch "output.map"
)

add_executable(${PROJECT_NAME} "main.cpp" "output.map")

set_target_properties(
    ${PROJECT_NAME} 
    PROPERTIES 
        LINK_DEPENDS "${CMAKE_CURRENT_BINARY_DIR}/output.map"
)
Florian
  • 39,996
  • 9
  • 133
  • 149