summaryrefslogtreecommitdiff
path: root/cmake/Modules/SourceDistribution.cmake
blob: c4dae25241b2ca042b15b13b614a9b39df192df1 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
# - a CMake module that helps to create a source distribution
#
# This module provide some macros that setup a source distribution.
# In contrast to standard CPack processing this is a very lightweight
# module that works very fast. The source distribution module enables
# the Cmake user to add indivdiual files and directories and thus
# provides a more fine grained control than CPack.
#
# The module works similar to the standard CMake INSTALL command: the
# macros of this module prepare CMake files (cmake_src_dist.cmake) that
# contain all necessary commands to create the distribution directoy.
# The make target 'src_dist' executes the commands and builds the
# compressed tar file of the source distribution.  
#
# Usage:
#  src_distribution_init([NOT_INCLUDE_DEFAULT] [<distribtuion name>])
#    Initializes the source distribution functions. Each CMakeList.txt
#    that distributes sources must call this macro before it can use
#    other source distrbution macros. 
#    Only the first call from the top level CMakeLists.txt uses the
#    distribution name argument. All subsequent call silently ignore it.
#    The macro sets the distribution name to ${PROJECT_NAME}-{VERSION}
#    if no distribution name is provided.
#    The macro automatically includes some default files and directories 
#    into the distribution: CMakeLists.txt and the cmake directory. 
#    Set NOT_INCLUDE_DEFAULT to disable this function.
#    The macro creates a make target 'src_dist'. This target executes
#    all operations to create the distribution directory structure and
#    to create the compressed tar file <distrbution name>.tar.gz. The
#    source distribution directory can be deleted afterwards.
#
#  add_src_dist_dirs(<DIRECTORY> [<DIRECTORY>]*)
#    Works imilar to the normal add_subdirectory command of CMake.
#    This call adds a subdirectory that contains sources or other
#    files that go into a source distribution. The subdirecty must
#    contain a CMakeLists.txt file that also uses the source distrbution
#    macros.
#
#  add_src_dist_files(<FILENAME> [<FILENAME>]*)
#    Adds one or more files to the source distrbution.
#
# Eaxample:
#
# include(SourceDistrbution)
#
# The following call initializes the module and sets the distrbution's
# name to 'mySourceDist'. The macro creates a directory with this name
# in the current build directory and include the standard CMakeLists.txt
# file and the 'cmake' directory (it it exists) into the distribution.
#
# src_distribution_init(mySourceDist)
#
#  Now add some files (assumes ${src_files} was set previously):
# add_src_dist_files(README LICENSE ${src_files})
#
#  Now add a subdirectoy, in this case an include directory:
# add_src_dist_dirs(include) 
#
#
# ---- internal macros ----
#
# This macro gets the current directory relative to CMAKE_SOURCE_DIR 
# and sets an internal variable to the current distribution directory.
# Another variable holds the current path to the CMake command file.
# Other macros use these variable to construct commands
# to build the distribution structure.
#
MACRO (_set_src_dist_scope_vars)
STRING(REPLACE "${CMAKE_SOURCE_DIR}" "" _src_dist_subdir "${CMAKE_CURRENT_SOURCE_DIR}")
if (NOT _src_dist_subdir)
    set(_src_dist_fulldir ${SRC_DIST_DIR})
else()
    set(_src_dist_fulldir ${SRC_DIST_DIR}${_src_dist_subdir})
endif()
set(_src_dist_cmd_file_path ${CMAKE_CURRENT_BINARY_DIR}/${_SRC_DIST_CMD_FILE_NAME})
ENDMACRO()

#
# Check for the NOT_INCLUDE_DEFAULT option.
#
MACRO(_src_dist_parse_options _result _default _length)
  set(${_default} TRUE)

  foreach(_arg ${ARGN})
    if (_arg STREQUAL "NOT_INCLUDE_DEFAULT")
         set(${_default} FALSE)
    endif()
  endforeach()

  set(${_result} ${ARGN})
  list(LENGTH ${_result} ${_length})
  if (${_length} GREATER 0)
    list(REMOVE_ITEM ${_result} "NOT_INCLUDE_DEFAULT")
  endif()
  # recompute length of list
  list(LENGTH ${_result} ${_length})

ENDMACRO()


#
# This macro initializes the source distribution package.
# Only the top-level initialization macro init_src_distribution()
# calls this internal macro.
#
MACRO (_src_dist_internal_init)
# internal variable for distribution cmake file
set(_SRC_DIST_CMD_FILE_NAME "cmake_src_dist.cmake")

if (${_src_dist_dirlist_length} EQUAL 0)
   set(_src_dist_tardir ${PROJECT_NAME}-${VERSION})
else()
   list(GET _src_dist_dirlist 0 _src_dist_tardir)
endif()
set(SRC_DIST_DIR ${CMAKE_BINARY_DIR}/${_src_dist_tardir})

message(STATUS "Source distribution direcrory set to: ${SRC_DIST_DIR}")

_set_src_dist_scope_vars()
file(REMOVE ${_src_dist_cmd_file_path})

# fill in first commands into the distribution cmake file. Calling
# 'make src_dist' executes the stored commands and prepares the source
# distrubtion.
#
file(APPEND ${_src_dist_cmd_file_path} "
# clear contents of an existing distribution directory
file(REMOVE_RECURSE ${SRC_DIST_DIR})
")

add_custom_target(src_dist 
  COMMAND ${CMAKE_COMMAND} -P ${_src_dist_cmd_file_path}
  COMMAND ${CMAKE_COMMAND} -E tar cfj ${SRC_DIST_DIR}.tar.bz2 ${_src_dist_tardir}
  COMMAND ${CMAKE_COMMAND} -E remove_directory ${SRC_DIST_DIR}
  )

ENDMACRO()

################# User visible macros ###################
#
MACRO(src_distribution_init)

# clear old src distribution cmake command file
_src_dist_parse_options(_src_dist_dirlist _src_dist_default _src_dist_dirlist_length ${ARGN})

if (NOT DEFINED _SRC_DIST_INIT)
    _src_dist_internal_init()
    set(_SRC_DIST_INIT TRUE)
else()
  _set_src_dist_scope_vars()
  file(REMOVE ${_src_dist_cmd_file_path})
endif()

if(_src_dist_default)
  if(IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/cmake")
    set(_src_dist_list_tmp)
    # Get all files names in cmake subdir
    # Unfortunately CMake also globs all directories and files that start
    # with . - that is not the same as shell behaviour
    file(GLOB_RECURSE _src_dist_names_tmp RELATIVE 
         ${CMAKE_CURRENT_SOURCE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake/*)
    #
    # Remove all file names that contain a name that start with .
    foreach(_nm ${_src_dist_names_tmp})
      string(REGEX REPLACE .*/\\..* "" _nm ${_nm})
      set(_src_dist_list_tmp ${_src_dist_list_tmp} ${_nm})
    endforeach()
    add_src_dist_files(${_src_dist_list_tmp})
  endif()
  if(EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt")
    file(APPEND ${_src_dist_cmd_file_path} "
FILE(INSTALL DESTINATION \"${_src_dist_fulldir}\" TYPE FILE FILES 
\"${CMAKE_CURRENT_SOURCE_DIR}/CMakeLists.txt\") 
") 
  endif()
endif()

ENDMACRO()

# Add a subdirectory to the src distribution
#
MACRO(add_src_dist_dirs)

foreach(_dir ${ARGN})
    if (NOT EXISTS ${CMAKE_CURRENT_SOURCE_DIR}/${_dir}/CMakeLists.txt)
        message(FATAL_ERROR 
	    "Soure distribution subdirectory \"${CMAKE_CURRENT_SOURCE_DIR}/${_dir}\" does not contain a CMakeLists.txt")
    endif()

    # include subdirectory's distribution cmake command file
    file(APPEND ${_src_dist_cmd_file_path} "
include(\"${CMAKE_CURRENT_BINARY_DIR}/${_dir}/${_SRC_DIST_CMD_FILE_NAME}\")
")
endforeach()
ENDMACRO()

#
# Add files to the src distribution. The handles and install files
# that are in the same directory as the current source as well as files
# in sub directories of the current source (with relative path).
#
MACRO(add_src_dist_files)

foreach(_file ${ARGN})
  get_filename_component(_src_dist_tmp_path ${_file} PATH)
#  string(REPLACE "${CMAKE_SOURCE_DIR}" "" _src_dist_tmp_path "${_src_dist_tmp_path}")
  if(_src_dist_tmp_path)
    set(_src_dist_tmp_path ${_src_dist_fulldir}/${_src_dist_tmp_path})
  else ()
    set(_src_dist_tmp_path ${_src_dist_fulldir})
  endif()
  file(APPEND ${_src_dist_cmd_file_path} "
FILE(INSTALL DESTINATION \"${_src_dist_tmp_path}\" TYPE FILE FILES
    \"${CMAKE_CURRENT_SOURCE_DIR}/${_file}\") ")

endforeach()

ENDMACRO()