[CMake] Force target to always run last?

Patrick Boettcher patrick.boettcher at posteo.de
Thu May 18 17:07:49 EDT 2017


Now that you described in more detail what you're trying to do I
realized that I had a similar problem to solve.

It's about generating packages for an arm-based linux-build
(Yocto-based). I decided against integrating my build into the
Yocto-build and instead I'm using cmake to cross-compile the
executables and libraries (C and C++).

Packaging is done with an IPK-file via a script launched by cmake
as the last step of the build process.

For each library and executable which belongs to a future ipk-package
I'm adding an install()-command which will, when the install-target
is run, place the files into a directory inside the build dir. This
directory is a dedicated one for the package:

For example:

top-level:

  set(PACKAGE_DIR ${CMAKE_BINARY_DIR}/common-exe-package)

Somewhere in the hierarchy of the project's CMakeLists.txt

  add_library(common src.cpp [..])
  install(TARGETS common
          DESTINATION ${PACKAGE_DIR}/usr/lib)

and again somewhere else

  add_executable(exe exe.cpp)
  target_link_libraries(exe PRIVATE common)
  install(TARGETS exe
          DESTINATION ${PACKAGE_DIR}/usr/bin)

Then I create a custom_target to create the package:

  add_custom_target(
    ipk-common-exe
    COMMAND
        [..] # commands to finalize the ipk-tree and
             # tar xfz ... to make the ipk-files
    COMMENT "creating common-exe IPK"
    WORKING_DIRECTORY
        ${PACKAGE_DIR}
  )
  
  # add dependencies to a install-and-strip-target
  add_dependencies(ipk-common-exe install-and-strip)

The "install-and-strip"-target is defined at the top-level

  add_custom_target(
      install-and-strip
      COMMAND ${CMAKE_COMMAND} --build ${CMAKE_BINARY_DIR} 
              --target install/strip)

the built-in install/strip-target has a dependency to all
targets use with install(TARGET ...) 

I'm using ninja and make -jX, both work in parallel. I'm build several
packages in one cmake-build. Works like a charm.

An additional bonus is that the install-target also removed RPATHs from
executables. 

HTH,
--
Patrick.




On Thu, 18 May 2017 11:16:47 -0500
Robert Dailey <rcdailey.lists at gmail.com> wrote:

> So let me go over the problem I'm trying to solve, because it's
> possible at this point I'm over-engineering it, but it's hard to fix.
> 
> So my build process is for native shared library targets that
> eventually get included in an APK for Android. I'm using the NDK
> toolchain to build my native targets. The general flow from nothing to
> complete APK is as follows:
> 
> 1. Build all native library targets
> 2. Copy native *.so outputs from the CMake build to `libs/armeabi-v7a`
> in the android project directory (where the src, res, and other
> android directories are located)
> 3. Run custom commands that basically invoke 'ant release', and since
> I positioned the *.so files under 'libs' they get packaged with the
> APK itself.
> 
> This is how I provide support for using CMake to build native, run
> java build, and perform APK packaging.
> 
> There's a lot of setup that happens in CMake in order to make sure the
> 'ant release' command behaves as expected. I have to handle a few
> corner cases:
> 
> * Each new build of the custom target that runs the 'ant release'
> command has to only contain the *.so files that were built during that
> run
> * Various third-party libraries (pre-compiled *.so files) have to also
> be copied to libs/armeabi-v7a for only certain android projects,
> because we do not want duplicated *.so files across multiple android
> libraries (ant release will fail if there are duplicate *.so files
> across android project dependencies)
> 
> So given this, my complete pipeline is as follows:
> 
> 1. A `android_clean_libs` custom target is run which iterates all
> known native targets with mapped java projects and completely deletes
> its 'libs' directory (this is a forced clean prior to building)
> 2. A `copy_dlls` target runs next, which copies third party
> (precompiled) *.so files to a single common java project, in its
> 'libs/armeabi-v7a' directory.
> 3. Each native target now builds in parallel, as a post-build event it
> copies its output *.so file to its respective libs/armeabi-v7a
> directory for packaging.
> 4. A final 'package' custom target runs which runs 'ant release' on
> the bottom-most android project (that is not a library target by
> itself).
> 
> The part I don't like here is step #1. I don't like the clean to
> require keeping track of a global property of a list of directories to
> remove. Ideally, #1 should run as a post-build event during step 3.
> Basically each native target should delete its 'libs' directory prior
> to copying its own *.so target to that directory. However, I can't do
> this because of step #2. Step 2 must happen first, because it's the
> only way I can guarantee that it will execute regardless of which
> target I build (all, or specific target). I make `copy_dlls` a
> dependency of every other target, so it always runs. If I could force
> it to run *last*, then I could simplify step 1.
> 
> Sorry if this is too much information or if I've not explained things
> clearly, but I wanted to hash out the details because maybe there is a
> better approach. I'm willing to start from scratch on this if it
> improves the design of the targets.
> 
> Thanks again!!
> 
> 
> On Thu, May 18, 2017 at 10:51 AM, David Cole <DLRdave at aol.com> wrote:
> > I'm sorry, I misunderstood that you wanted it to run last regardless
> > of what target you are building. I was assuming you wanted it to
> > happen when you build the "all" target. I didn't think you wanted to
> > run it after any other *individual* target which you might specify.
> >
> > I don't know of an easy way to do that. You could add a custom
> > command as a post-build command on every single target, but that
> > seems like it wouldn't work for you either, as it would run the
> > command potentially multiple times, with no way to tell whether
> > you're being called last or not.
> >
> > Sorry.
> >
> > Why does this need to run after the build of any individual target?
> > Why not just say there are two ways to get it to run: build "all" or
> > explicitly build it after you build the other individual thing you
> > want?
> >
> >
> >
> >
> > On Thu, May 18, 2017 at 10:24 AM, Robert Dailey
> > <rcdailey.lists at gmail.com> wrote:  
> >> David,
> >>
> >> Thanks for your help. So if I do it as you suggest, this will also
> >> require I specify `ALL` to add_custom_target(), correct? If I do it
> >> this way, will it still run even if it isn't a dependency of the
> >> target I'm building?
> >>
> >> Let me set up a simple scenario for my own understanding. Suppose I
> >> have the following targets:
> >>
> >> * A (add_library target)
> >> * B (add_library target)
> >> * C (add_custom_target target)
> >>
> >> Dependencies:
> >>
> >> B depends on A
> >> C depends on B and A
> >>
> >> Normally if I build B, only A and B will build. However, if C was
> >> set up using `ALL`, will it build C when I build B? So the
> >> expected build order in this case would be:
> >>
> >> 1. A
> >> 2. B
> >> 3. C
> >>
> >> Thanks in advance.
> >>
> >> On Wed, May 17, 2017 at 4:26 PM, David Cole <DLRdave at aol.com>
> >> wrote:  
> >>> The way I know how to do this is to add it last at the bottom of
> >>> the top-level CMakeLists.txt file, and then use add_dependencies
> >>> to make it depend on all other targets. (Or at least all other
> >>> "leaf" targets, which further depend on others, ... the sum of
> >>> which is "all other targets" besides the new "last" target.)
> >>>
> >>> So it's not pretty, but it's possible.
> >>>
> >>>
> >>> HTH,
> >>> David C.
> >>>
> >>>
> >>>
> >>> On Wed, May 17, 2017 at 11:36 AM, Robert Dailey
> >>> <rcdailey.lists at gmail.com> wrote:  
> >>>> I have a custom target that must meet the following requirements:
> >>>>
> >>>> * It must always run, regardless of what subset of other targets
> >>>> are being built
> >>>> * It must always be the very last thing run. In parallelized
> >>>> builds, it must wait until all other targets are done building
> >>>> before starting, so that it is the very last target run, and
> >>>> should not run in parallel  with others.
> >>>>
> >>>> Is this possible? I'm willing to use hackery if needed...
> >>>>
> >>>> Running CMake 3.8.0. Thanks!
> >>>> --
> >>>>
> >>>> Powered by www.kitware.com
> >>>>
> >>>> Please keep messages on-topic and check the CMake FAQ at:
> >>>> http://www.cmake.org/Wiki/CMake_FAQ
> >>>>
> >>>> Kitware offers various services to support the CMake community.
> >>>> For more information on each offering, please visit:
> >>>>
> >>>> CMake Support: http://cmake.org/cmake/help/support.html
> >>>> CMake Consulting: http://cmake.org/cmake/help/consulting.html
> >>>> CMake Training Courses: http://cmake.org/cmake/help/training.html
> >>>>
> >>>> Visit other Kitware open-source projects at
> >>>> http://www.kitware.com/opensource/opensource.html
> >>>>
> >>>> Follow this link to subscribe/unsubscribe:
> >>>> http://public.kitware.com/mailman/listinfo/cmake  



More information about the CMake mailing list