13

According to FAQ, CMake doesn't create a make dist target and source package can be created using CPack. But CPack just makes a tarball of the source directory with all files that don't match patterns in CPACK_SOURCE_IGNORE_FILES.

On the other hand, make dist generated by autotools bundles only files it knows about, mostly sources needed for compilation.

Anyone has a smart way of making a source package with only files that are specified in CMakeLists.txt (and its dependencies)?

marcin
  • 3,351
  • 1
  • 29
  • 33
  • Not an answer but you could use your VCS to do that, for instance [`git archive`](http://schacon.github.com/git/git-archive.html) if you are using git. – Simon Mar 09 '12 at 23:50
  • There is a blog post from 2009, but still kind of clumsy: http://agateau.com/2009/cmake-and-make-dist/ – usr1234567 Mar 12 '15 at 07:09
  • Not an answer but a hint that you're not alone: in some project we maintained and manually and auto generated text files called `artefacts.txt` which we then used used to create a distribution (in a separate build target). The text files contained source (in `src` or `build` folder) destination and some implicit rules (e.g. py => pyc) – frans Mar 12 '15 at 11:12
  • 1
    Probably explicitly `install(FILES ... DESTINATION ..)` is the way to go. Maybe the list can be generated, but I'd rather maintain it by hand. I knot, this is not a smart way. – usr1234567 Mar 20 '15 at 22:13
  • 1
    Possible duplicate of [Get all source files a target depends on in CMake](http://stackoverflow.com/questions/39448892/get-all-source-files-a-target-depends-on-in-cmake) – Florian Jan 01 '17 at 21:48

2 Answers2

2

I've been thinking about this for a while and I won't pretend I can simulate a make dist without having this directly supported by CMake itself.

The problem is that you can add a lot of file dependencies with CMake on the one side (e.g. to pre-build libraries) and on the other side CMake does not know about dependencies directly checked by the generated build environment itself (e.g. any header dependencies).

So here is a code that just collects all CMakeList.txt and source files given with any build targets:

function(make_dist_creator _variable _access _value _current_list_file _stack)
    if (_access STREQUAL "MODIFIED_ACCESS")
        # Check if we are finished (end of main CMakeLists.txt)
        if (NOT _current_list_file)
            get_property(_subdirs GLOBAL PROPERTY MAKE_DIST_DIRECTORIES)
            list(REMOVE_DUPLICATES _subdirs)
            foreach(_subdir IN LISTS _subdirs)
                list(APPEND _make_dist_sources "${_subdir}/CMakeLists.txt")
                get_property(_targets DIRECTORY "${_subdir}" PROPERTY BUILDSYSTEM_TARGETS)
                foreach(_target IN LISTS _targets)
                    get_property(_sources TARGET "${_target}" PROPERTY SOURCES)
                    foreach(_source IN LISTS _sources)
                        list(APPEND _make_dist_sources "${_subdir}/${_source}")
                    endforeach()
                endforeach()
            endforeach()

            add_custom_target(
                dist
                COMMAND "${CMAKE_COMMAND}" -E tar zcvf "${CMAKE_BINARY_DIR}/${PROJECT_NAME}.tar.gz" -- ${_make_dist_sources}
                COMMENT "Make distribution ${PROJECT_NAME}.tar.gz"
                WORKING_DIRECTORY "${CMAKE_SOURCE_DIR}"
            )
            message("_make_dist_sources = ${_make_dist_sources}")
        else()
            # else collect subdirectories in my source dir
            file(RELATIVE_PATH _dir_rel "${CMAKE_SOURCE_DIR}" "${_value}")
            if (NOT _dir_rel MATCHES "\.\.")
                set_property(GLOBAL APPEND PROPERTY MAKE_DIST_DIRECTORIES "${_value}")
            endif()
        endif()
    endif()
endfunction()

variable_watch("CMAKE_CURRENT_LIST_DIR" make_dist_creator)

Note: The used BUILDSYSTEM_TARGETS property needs at least CMake version 3.7

I see the code above as an starting point and prove of concept. You could add libraries, headers, etc. on a need-by basis, but you should probably just tweak to do your bidding.

As a starting point see e.g. the link @usr1234567 provided in the comments.

References

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

Simon is correct above but does not give a full answer. With git you can generate a compatible tar ball archive with the git archive command.

This example with the version is compatible with make dist of yesteryear.

git archive --format=tar.gz -o my-repo-0.01.tar.gz --prefix=my-repo-0.01/ master

See: https://gist.github.com/simonw/a44af92b4b255981161eacc304417368

  • "git archive" appears to be an alias of "tar" followed by "gzip". "make dist" is a mechanism where all files required for the build and no others are packaged, which is a different thing. They are not comparable. – Graham Leggett Mar 12 '23 at 09:08