0

I'm building two targets using:

add_library(tgt1 SHARED a.cpp)
add_library(tgt2 SHARED b.cpp)

After both are built, I need to run a post build step that depends on both targets. I tried many combinations of the following but with no success:

add_custom_target(final_tgt DEPENDS tgt1 tgt2)
add_custom_command(TARGET final_tgt POST_BUILD COMMAND <command> ARGS <args>)

The final target would simply not build, even though its build.make contains the custom command.

Tried to use ALL for the custom target, however make attempts to build it first while missing the first targets.

And I can't use an add_library or add_executable for the final target, since they require specifying source files.

What is the correct way to do it?

===================================

Edit: below is a minimal verifiable source code. What it attempts to do is to compile code (for Mac) in two architectures and as a post-build to create a universal binary using lipo:

cmake_minimum_required(VERSION 2.8)
set(icpc_req_path "/usr/local/bin/icpc-16.0.146")

set(CMAKE_CXX_COMPILER "${icpc_req_path}")

project("CMakeTest")
set(SOURCE_FILES a.cpp)

set (TARGET_NAME "TGT")
set(TARGETS "")
set(ARCHITECTURES i386 x86_64)

foreach(ar ${ARCHITECTURES})
    set(CMAKE_CXX_FLAGS_RELEASE "")
    set(CMAKE_CXX_FLAGS_DEBUG "")
    set(CMAKE_CXX_FLAGS "")

    add_library(TGT_${ar} SHARED ${SOURCE_FILES})
    set_target_properties(${TARGET_NAME}_${ar}
        PROPERTIES COMPILE_FLAGS "-arch ${ar} -xSSE3")
    set_target_properties(${TARGET_NAME}_${ar}
        PROPERTIES LINK_FLAGS "-arch ${ar}")
    set(TARGETS "${TARGETS};lib${TARGET_NAME}_${ar}.dylib")
endforeach(ar)

message("Targets: ${TARGETS}")
add_custom_target(${TARGET_NAME} DEPENDS ${TARGETS})
add_custom_command(TARGET ${TARGET_NAME} POST_BUILD
     COMMAND "lipo"
     ARGS "-create" ${TARGETS} "-output" "${TARGET_NAME}.dylib")

And the contents of a.cpp is:

int main(){}
Unapiedra
  • 15,037
  • 12
  • 64
  • 93
gil_mo
  • 575
  • 1
  • 6
  • 27
  • Could you _please_ improve the question by providing a [Minimal, Complete and Verifiable](https://stackoverflow.com/help/mcve) example? To answer the question properly, I would like to know what is, and why the dependency is to both targets. – Unapiedra May 06 '18 at 22:07
  • 1
    I've added my minimal code. – gil_mo May 07 '18 at 13:11
  • I've updated my answer to fit for your specific question. – Unapiedra May 14 '18 at 01:01

2 Answers2

2

add_custom_command comes in two flavors: Producing new output, and acting on single targets. Docs

What is the command that you are calling doing? Is it in any way producing results (new files, etc)? If so, use add_custom_command like this:

add_custom_command(
  OUTPUT <output-file>
  DEPENDS tgt1 tgt2
  COMMAND <command>
  ARGS <args>
  COMMENT "Running  <command> on targets tgt1 and tgt2."
)

Using the second variant of add_custom_command which does not have an OUTPUT argument, because it changes a <target> as POST_BUILD (or pre-build, pre-link) step, needs a single target. So, which one of tgt1 and tgt2 gets modified by your <command>?

Let's assume that tgt1 gets modified in the POST_BUILD step and tgt2 is untouched. Then you can do it like this:

add_library(tgt2 SHARED b.cpp)

add_library(tgt1 SHARED a.cpp)
add_custom_command(
  TARGET tgt1 POST_BUILD
  COMMAND <command>
  ARGS <args>
)
add_dependencies(tgt1 tgt2) # tgt1 depends on tgt2 because
# POST_BUILD-step is just the final step to build 'tgt1'
# NOTE: It is incorrect to modify 'tgt2' as POST_BUILD step for tgt1.
#       So this example expects no changes to tgt2 in add_custom_command.

-- EDIT after more details given in question:

Working example

CMakeLists.txt

# I don't have 'icpc' and could not find it easily available for macOS.
# Instead, let's create a file "TGT" where contents are the two hashes of the two
# libraries, like done in 'Th.Thielemann's answer.
cmake_minimum_required(VERSION 3.10)
project(q50198141)

add_library(Big SHARED library1.cpp)
add_library(Foo SHARED library2.cpp)

add_custom_command(OUTPUT combined
    COMMAND ${CMAKE_CURRENT_SOURCE_DIR}/combine.sh
    ARGS $<TARGET_FILE:Big> $<TARGET_FILE:Foo> combined
    DEPENDS Big Foo combine.sh
    COMMENT Build output 'combined'
)
add_custom_target(run_combined ALL DEPENDS combined)

combined.sh (Make sure to be excecutable!)

#!/bin/bash

# Hardcoded for q50198141    
# Args: In1 In2 Out
md5sum $1 $2 > $3
Unapiedra
  • 15,037
  • 12
  • 64
  • 93
1

The following example works for me.

Two targets independent from each other. One custom target depending from both.

add_library(Big SHARED ${SOURCES_BIG})
add_library(Foo SHARED ${SOURCES_FOO})

add_custom_target(pack ALL
    COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}Big${CMAKE_SHARED_LIBRARY_SUFFIX}
    COMMAND ${CMAKE_COMMAND} -E md5sum ${CMAKE_CURRENT_BINARY_DIR}/${CMAKE_SHARED_LIBRARY_PREFIX}Foo${CMAKE_SHARED_LIBRARY_SUFFIX}
    DEPENDS Big Foo
    COMMENT Build target pack
)

Note: Calculating the hash of the code is just to show whether targets are rebuild on changes or not.

Unapiedra
  • 15,037
  • 12
  • 64
  • 93
Th. Thielemann
  • 2,592
  • 1
  • 23
  • 38
  • Tried it, specifying ALL causes this error: *** No rule to make target `', needed by `'. Stop. - During the CMake process. – gil_mo May 08 '18 at 07:19
  • @gil_mo The posted example works fine for me! (But it does not completely answer your question: you want `add_custom_command` b/c you need to produce a real output.) – Unapiedra May 14 '18 at 00:31