# - adds support for the 'make dist' and 'make distcheck' commands -*- cmake -*- # # Usage: # add_makedist() ... called exactly once per project in the top-level # CMakeLists.txt; it adds the 'dist' and 'distcheck' # targets # # enable_makedist(...list-of-sources...) # ... called in every CMakeLists.txt which has source # files. Beside the listed sources, the CMakeLists.txt # file itself and all files listed in ${EXTRA_DIST} # will be added to the tarball # # This module implements the 'make dist' and 'make distcheck' # commands. When sources are given to enable_makedist() which are # having the 'GENERATED' property, they will be ignored unless # they are in ${EXTRA_DIST} or are having the EXTRADIST property. # # It supports the following variables: # # MAKEDIST_TMPDIR ... directory for temporary files # MAKEDIST_PKGBASE ... basename of the created tarball; defaults to # ${PACKAGE}-${VERSION} (see below) # MAKEDIST_TARFLAGS ... flags which are used to create the tarball # MAKEDIST_CMAKEFLAGS # ... flags which are given to 'cmake' by 'make distcheck' # MAKEDIST_BUILDTARGETS # ... the build-targets tried by 'make distcheck'; # defaults to nothing (--> all) # MAKEDIST_CHECKTARGETS # ... the check-targets tried by 'make distcheck'; # defaults to 'test' # MAKEDIST_INSTALLTARGETS # ... the install-targets tried by 'make distcheck'; # defaults to 'install' # # EXTRA_DIST ... set per CMakeLists.txt file to add non-source or # generated source files to the tarball # # Unless MAKEDIST_PKGBASE is modified, the following variables are # required to be set: # # PACKAGE ... name of the package (e.g. 'foo') # VERSION ... version of the package (e.g. '0.1.2') # # # Example: # --- top-level CMakeLists.txt --- # set(PACKAGE foo) # set(VERSION 1.2.3) # # find_package(MakeDist) # add_subdirectory(foo) # # add_makedist() # # set(EXTRA_DIST COPYING) # enable_makedist(config.h.in) # # --> adds ./COPYING and ./config.h.in to the tarball # # --- foo/CMakeLists.txt --- # set_source_files_properties( # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-A.h # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-B.h # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-C.h # PROPERTIES GENERATED TRUE) # # set_source_files_properties( # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-A.h # PROPERTIES EXTRADIST TRUE) # set(EXTRA_DIST ${CMAKE_CURRENT_BINARY_DIR}/generated-file-B.h) # # enable_makedist( # foo.c # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-A.h # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-B.h # ${CMAKE_CURRENT_BINARY_DIR}/generated-file-C.h) # # --> adds ./foo/generated-file-{A,B}.h and ./foo/foo.c to the # tarball, but not ${CMAKE_CURRENT_BINARY_DIR}/generated-file-C.h # # TODO/limitations: # * works probably with the 'make' generator only # * requires at least a SUSv3/POSIX compliant system; some parts # (e.g. bzip2-tarballs) depend on some GNUisms; this should be # made configurable perhaps # * there could be added some more tests (e.g. gnit-style (check for # existence of required files and a proper VERSION format)) # * it is somehow ugly, to see hundreds of 'Built target .distdir' # messages # * is is ugly that all sources must be specified for enable_makedist(); # there should be added support to 'cmake' to enumerate targets and # their sources # Copyright (C) 2006 Enrico Scholz # # Redistribution and use, with or without modification, are permitted # provided that the following conditions are met: # # 1. Redistributions must retain the above copyright notice, this # list of conditions and the following disclaimer. # 2. The name of the author may not be used to endorse or promote # products derived from this software without specific prior # written permission. # # THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR # IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED # WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE # ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY # DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL # DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE # GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS # INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER # IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR # OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN # IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. set(MakeDist_FOUND 1) set(MAKEDIST_TMPDIR "${CMAKE_BINARY_DIR}/.make-dist" CACHE PATH "directory for temporary files created by'make dist*'") set(MAKEDIST_PKGBASE "${PACKAGE}-${VERSION}" CACHE STRING "basename of the tarball created by 'make dist*'") set(MAKEDIST_TARFLAGS --bzip2 --owner=0 --group=0 CACHE STRING "flags used by 'make dist' to create the tarball") set(MAKEDIST_TARBALL "${CMAKE_BINARY_DIR}/${MAKEDIST_PKGBASE}.tar.bz2" CACHE PATH "tarball created by 'make dist'") set(MAKEDIST_CMAKEFLAGS -DBUILD_SHARED_LIBS:BOOL=ON CACHE STRING "flags which are given to 'cmake' by 'make distcheck'") set(MAKEDIST_BUILDTARGETS "" CACHE STRING "build-target(s) tried by 'make distcheck'") set(MAKEDIST_CHECKTARGETS test CACHE STRING "check-target(s) tried by 'make distcheck'") set(MAKEDIST_INSTALLTARGETS install CACHE STRING "install-target(s) tried by 'make distcheck'") mark_as_advanced( MAKEDIST_TMPDIR MAKEDIST_PKGBASE MAKEDIST_TARBALL MAKEDIST_BUILDTARGETS MAKEDIST_CHECKTARGETS MAKEDIST_INSTALLTARGETS) set(MAKEDIST_TARDIR "${MAKEDIST_TMPDIR}/tar/${MAKEDIST_PKGBASE}") set(MAKEDIST_CHECKDIR "${MAKEDIST_TMPDIR}/check") macro(enable_makedist) add_custom_target(.distdir) set_source_files_properties(.distdir PROPERTIES SYMBOLIC TRUE GENERATED TRUE) foreach(__makedist_i ${EXTRA_DIST}) set_source_files_properties("${__makedist_i}" PROPERTIES EXTRADIST TRUE) endforeach(__makedist_i) foreach(__makedist_source CMakeLists.txt ${EXTRA_DIST} ${ARGN}) get_filename_component(__makedist_full_cur_path "${__makedist_source}" ABSOLUTE) get_source_file_property(__makedist_generated "${__makedist_source}" GENERATED) get_source_file_property(__makedist_extradist "${__makedist_source}" EXTRADIST) if(NOT __makedist_generated) file(RELATIVE_PATH __makedist_cur_path "${CMAKE_SOURCE_DIR}" "${__makedist_full_cur_path}") elseif(__makedist_extradist) file(RELATIVE_PATH __makedist_cur_path "${CMAKE_BINARY_DIR}" "${__makedist_full_cur_path}") else(__makedist_extradist) set(__makedist_cur_path) endif(NOT __makedist_generated) if(__makedist_cur_path) get_filename_component(__makedist_tmp "${MAKEDIST_TARDIR}/${__makedist_cur_path}" PATH) add_custom_command(TARGET .distdir COMMAND mkdir -p "${__makedist_tmp}" COMMAND cp -a "${__makedist_full_cur_path}" "${__makedist_tmp}/" DEPENDS ${__makedist_source}) else(__makedist_cur_path) message(STATUS "skipping ${__makedist_source}") endif(__makedist_cur_path) endforeach(__makedist_source) endmacro(enable_makedist) macro(add_makedist) set_source_files_properties(dist distcheck .distcheck PROPERTIES SYMBOLIC TRUE GENERATED TRUE) add_custom_target(dist # cleanup tmpdir COMMAND chmod -R u+Xw "${MAKEDIST_TMPDIR}" 2>/dev/null || : COMMAND rm -rf "${MAKEDIST_TMPDIR}" # execute 'make .distdir' COMMAND ${CMAKE_MAKE_PROGRAM} .distdir # set proper permissions COMMAND chmod -R go-w,a+rX,u+w "${MAKEDIST_TARDIR}" # create the tarball COMMAND cd "${MAKEDIST_TARDIR}/.." && tar cf "${MAKEDIST_TARBALL}\${MAKEDIST_TARBALL_TMP}" ${MAKEDIST_TARFLAGS} ${MAKEDIST_PKGBASE} # cleanup tmpdir COMMAND rm -rf "${MAKEDIST_TMPDIR}" WORKING_DIRECTORY ${CMAKE_BINARY_DIR} ) add_custom_target(distcheck COMMAND rm -f "${MAKEDIST_TARBALL}".tmp COMMAND ${CMAKE_MAKE_PROGRAM} dist MAKEDIST_TARBALL_TMP=.tmp COMMAND ${CMAKE_MAKE_PROGRAM} .distcheck MAKEDIST_TARBALL_TMP=.tmp COMMAND rm -f "${MAKEDIST_TARBALL}" COMMAND mv -f "${MAKEDIST_TARBALL}.tmp" "${MAKEDIST_TARBALL}") add_custom_target(.distcheck # cleanup tmpdir and create directory layout COMMAND chmod -R u+Xw "${MAKEDIST_CHECKDIR}" 2>/dev/null || : COMMAND rm -rf "${MAKEDIST_CHECKDIR}" COMMAND mkdir -p "${MAKEDIST_CHECKDIR}/source" "${MAKEDIST_CHECKDIR}/build" # extract tarball COMMAND cd "${MAKEDIST_CHECKDIR}/source" && tar xf "${MAKEDIST_TARBALL}\${MAKEDIST_TARBALL_TMP}" ${MAKEDIST_TARFLAGS} # write-protect sources to detect modifies-sourcetree bugs COMMAND chmod -R a-w "${MAKEDIST_CHECKDIR}/source" # invoke 'cmake' COMMAND ${CMAKE_COMMAND} -E echo "executing initial cmake" COMMAND cd "${MAKEDIST_CHECKDIR}/build" && ${CMAKE_COMMAND} -DCMAKE_INSTALL_PREFIX:PATH="${MAKEDIST_CHECKDIR}/install" ${MAKEDIST_CMAKEFLAGS} "${MAKEDIST_CHECKDIR}/source/${MAKEDIST_PKGBASE}" COMMAND ${CMAKE_COMMAND} -E echo "initial cmake succeeded" # execute 'make build' and 'make check' COMMAND ${CMAKE_COMMAND} -E echo "building project" COMMAND cd "${MAKEDIST_CHECKDIR}/build" && ${CMAKE_MAKE_PROGRAM} ${MAKEDIST_BUILDTARGETS} COMMAND cd "${MAKEDIST_CHECKDIR}/build" && ${CMAKE_MAKE_PROGRAM} ${MAKEDIST_CHECKTARGETS} # execute 'make install' without DESTDIR COMMAND cd "${MAKEDIST_CHECKDIR}/build" && ${CMAKE_MAKE_PROGRAM} ${MAKEDIST_INSTALLTARGETS} DESTDIR= # write protect installation path to detect writing outside of DESTDIR COMMAND chmod -R a-w "${MAKEDIST_CHECKDIR}/install" # execute 'make install' with DESTDIR and move the files to a better location COMMAND cd "${MAKEDIST_CHECKDIR}/build" && ${CMAKE_MAKE_PROGRAM} ${MAKEDIST_INSTALLTARGETS} DESTDIR="${MAKEDIST_CHECKDIR}/install-tmp" COMMAND mv "${MAKEDIST_CHECKDIR}/install-tmp/${MAKEDIST_CHECKDIR}/install" "${MAKEDIST_CHECKDIR}/install-destdir" # generate list of files which were installed by the both 'make # install' commands above and compare them COMMAND cd "${MAKEDIST_CHECKDIR}/install" && find -type f | sort > ../files.install COMMAND cd "${MAKEDIST_CHECKDIR}/install-destdir" && find -type f | sort > ../files.destdir COMMAND cd "${MAKEDIST_CHECKDIR}" && diff files.install files.destdir # cleanup tmpdir COMMAND chmod -R u+Xw "${MAKEDIST_TMPDIR}" 2>/dev/null || : COMMAND rm -rf "${MAKEDIST_TMPDIR}" ) endmacro(add_makedist)