Move /MANIFEST flag into -E vs_link. This is so it can be used by the intel compiler...
[cmake.git] / Modules / ExternalProject.cmake
blobd5254f5785238653990e05bd36694fc642c56c6e
1 # - Create custom targets to build projects in external trees
2 # The 'ep_add' function creates a custom target to drive download,
3 # update/patch, configure, build, and install steps of an external
4 # project:
5 #  ep_add(<name>                 # Name for custom target
6 #    [DEPENDS projects...]       # Targets on which the project depends
7 #    [PREFIX dir]                # Root dir for entire project
8 #    [LIST_SEPARATOR sep]        # Sep to be replaced by ; in cmd lines
9 #    [TMP_DIR dir]               # Directory to store temporary files
10 #    [STAMP_DIR dir]             # Directory to store step timestamps
11 #   #--Download step--------------
12 #    [DOWNLOAD_DIR dir]          # Directory to store downloaded files
13 #    [DOWNLOAD_COMMAND cmd...]   # Command to download source tree
14 #    [CVS_REPOSITORY cvsroot]    # CVSROOT of CVS repository
15 #    [CVS_MODULE mod]            # Module to checkout from CVS repo
16 #    [CVS_TAG tag]               # Tag to checkout from CVS repo
17 #    [SVN_REPOSITORY url]        # URL of Subversion repo
18 #    [SVN_TAG tag]               # Tag to checkout from Subversion repo
19 #    [URL /.../src.tgz]          # Full path or URL of source
20 #   #--Update/Patch step----------
21 #    [UPDATE_COMMAND cmd...]     # Source work-tree update command
22 #    [PATCH_COMMAND cmd...]      # Command to patch downloaded source
23 #   #--Configure step-------------
24 #    [SOURCE_DIR dir]            # Source dir to be used for build
25 #    [CONFIGURE_COMMAND cmd...]  # Build tree configuration command
26 #    [CMAKE_COMMAND /.../cmake]  # Specify alternative cmake executable
27 #    [CMAKE_GENERATOR gen]       # Specify generator for native build
28 #    [CMAKE_ARGS args...]        # Arguments to CMake command line
29 #   #--Build step-----------------
30 #    [BINARY_DIR dir]            # Specify build dir location
31 #    [BUILD_COMMAND cmd...]      # Command to drive the native build
32 #    [BUILD_IN_SOURCE 1]         # Use source dir for build dir
33 #   #--Install step---------------
34 #    [INSTALL_DIR dir]           # Installation prefix
35 #    [INSTALL_COMMAND cmd...]    # Command to drive install after build
36 #    )
37 # The *_DIR options specify directories for the project, with default
38 # directories computed as follows.
39 # If the PREFIX option is given to ep_add() or the EP_PREFIX directory
40 # property is set, then an external project is built and installed
41 # under the specified prefix:
42 #   TMP_DIR      = <prefix>/tmp
43 #   STAMP_DIR    = <prefix>/src/<name>-stamp
44 #   DOWNLOAD_DIR = <prefix>/src
45 #   SOURCE_DIR   = <prefix>/src/<name>
46 #   BINARY_DIR   = <prefix>/src/<name>-build
47 #   INSTALL_DIR  = <prefix>
48 # Otherwise, if the EP_BASE directory property is set then components
49 # of an external project are stored under the specified base:
50 #   TMP_DIR      = <base>/tmp/<name>
51 #   STAMP_DIR    = <base>/Stamp/<name>
52 #   DOWNLOAD_DIR = <base>/Download/<name>
53 #   SOURCE_DIR   = <base>/Source/<name>
54 #   BINARY_DIR   = <base>/Build/<name>
55 #   INSTALL_DIR  = <base>/Install/<name>
56 # If no PREFIX, EP_PREFIX, or EP_BASE is specified then the default
57 # is to set PREFIX to "<name>-prefix".
58 # Relative paths are interpreted with respect to the build directory
59 # corresponding to the source directory in which ep_add is invoked.
61 # If SOURCE_DIR is explicitly set to an existing directory the project
62 # will be built from it.
63 # Otherwise a download step must be specified using one of the
64 # DOWNLOAD_COMMAND, CVS_*, SVN_*, or URL options.
65 # The URL option may refer locally to a directory or source tarball,
66 # or refer to a remote tarball (e.g. http://.../src.tgz).
68 # The 'ep_add_step' function adds a custom steps to an external project:
69 #  ep_add_step(<name> <step> # Names of project and custom step
70 #    [COMMAND cmd...]        # Command line invoked by this step
71 #    [COMMENT "text..."]     # Text printed when step executes
72 #    [DEPENDEES steps...]    # Steps on which this step depends
73 #    [DEPENDERS steps...]    # Steps that depend on this step
74 #    [DEPENDS files...]      # Files on which this step depends
75 #    [ALWAYS 1]              # No stamp file, step always runs
76 #    [WORKING_DIRECTORY dir] # Working directory for command
77 #    )
78 # The command line, comment, and working directory of every standard
79 # and custom step is processed to replace tokens
80 # <SOURCE_DIR>,
81 # <BINARY_DIR>,
82 # <INSTALL_DIR>,
83 # and <TMP_DIR>
84 # with corresponding property values.
86 # The 'ep_get' function retrieves external project target properties:
87 #  ep_get(<name> [prop1 [prop2 [...]]])
88 # It stores property values in variables of the same name.
89 # Property names correspond to the keyword argument names of 'ep_add'.
92 # Pre-compute a regex to match documented keywords for each command.
93 file(STRINGS "${CMAKE_CURRENT_LIST_FILE}" lines LIMIT_COUNT 100
94      REGEX "^#  (  \\[[A-Z_]+ [^]]*\\] +#.*$|[a-z_]+\\()")
95 foreach(line IN LISTS lines)
96   if("${line}" MATCHES "^#  [a-z_]+\\(")
97     if(_ep_func)
98       set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
99     endif()
100     string(REGEX REPLACE "^#  ([a-z_]+)\\(.*" "\\1" _ep_func "${line}")
101     #message("function [${_ep_func}]")
102     set(_ep_keywords_${_ep_func} "^(")
103     set(_ep_keyword_sep)
104   else()
105     string(REGEX REPLACE "^#    \\[([A-Z_]+) .*" "\\1" _ep_key "${line}")
106     #message("  keyword [${_ep_key}]")
107     set(_ep_keywords_${_ep_func}
108       "${_ep_keywords_${_ep_func}}${_ep_keyword_sep}${_ep_key}")
109     set(_ep_keyword_sep "|")
110   endif()
111 endforeach()
112 if(_ep_func)
113   set(_ep_keywords_${_ep_func} "${_ep_keywords_${_ep_func}})$")
114 endif()
117 function(_ep_parse_arguments f name ns args)
118   # Transfer the arguments to this function into target properties for the
119   # new custom target we just added so that we can set up all the build steps
120   # correctly based on target properties.
121   #
122   # We loop through ARGN and consider the namespace starting with an
123   # upper-case letter followed by at least two more upper-case letters
124   # or underscores to be keywords.
125   set(key)
127   foreach(arg IN LISTS args)
128     set(is_value 1)
130     if(arg MATCHES "^[A-Z][A-Z_][A-Z_]+$" AND
131         NOT ((arg STREQUAL "${key}") AND (key STREQUAL "COMMAND")) AND
132         NOT arg MATCHES "^(TRUE|FALSE)$")
133       if(_ep_keywords_${f} AND arg MATCHES "${_ep_keywords_${f}}")
134         set(is_value 0)
135       else()
136         if(NOT (key STREQUAL "COMMAND")
137           AND NOT (key STREQUAL "CVS_MODULE")
138           AND NOT (key STREQUAL "DEPENDS")
139           )
140           message(AUTHOR_WARNING "unknown ${f} keyword: ${arg}")
141         endif()
142       endif()
143     endif()
145     if(is_value)
146       if(key)
147         # Value
148         if(NOT arg STREQUAL "")
149           set_property(TARGET ${name} APPEND PROPERTY ${ns}${key} "${arg}")
150         else()
151           get_property(have_key TARGET ${name} PROPERTY ${ns}${key} SET)
152           if(have_key)
153             get_property(value TARGET ${name} PROPERTY ${ns}${key})
154             set_property(TARGET ${name} PROPERTY ${ns}${key} "${value};${arg}")
155           else()
156             set_property(TARGET ${name} PROPERTY ${ns}${key} "${arg}")
157           endif()
158         endif()
159       else()
160         # Missing Keyword
161         message(AUTHOR_WARNING "value '${arg}' with no previous keyword in ${f}")
162       endif()
163     else()
164       set(key "${arg}")
165     endif()
166   endforeach()
167 endfunction(_ep_parse_arguments)
170 define_property(DIRECTORY PROPERTY "EP_BASE" INHERITED
171   BRIEF_DOCS "Base directory for External Project storage."
172   FULL_DOCS
173   "See documentation of the ep_add() function in the "
174   "ExternalProject module."
175   )
177 define_property(DIRECTORY PROPERTY "EP_PREFIX" INHERITED
178   BRIEF_DOCS "Top prefix for External Project storage."
179   FULL_DOCS
180   "See documentation of the ep_add() function in the "
181   "ExternalProject module."
182   )
185 function(_ep_write_downloadfile_script script_filename remote local timeout)
186   if(NOT timeout)
187     set(timeout 30)
188   endif()
190   file(WRITE ${script_filename}
191 "message(STATUS \"downloading...
192      src='${remote}'
193      dst='${local}'\")
195 file(DOWNLOAD
196   \"${remote}\"
197   \"${local}\"
198   TIMEOUT ${timeout}
199   STATUS status
200   LOG log)
202 list(GET status 0 status_code)
203 list(GET status 1 status_string)
205 if(NOT status_code EQUAL 0)
206   message(FATAL_ERROR \"error: downloading '${remote}' failed
207   status_code: \${status_code}
208   status_string: \${status_string}
209   log: \${log}
211 endif()
213 message(STATUS \"downloading... done\")
217 endfunction(_ep_write_downloadfile_script)
220 function(_ep_write_extractfile_script script_filename filename tmp directory)
221   set(args "")
223   if(filename MATCHES ".tar$")
224     set(args xf)
225   endif()
227   if(filename MATCHES ".tgz$")
228     set(args xfz)
229   endif()
231   if(filename MATCHES ".tar.gz$")
232     set(args xfz)
233   endif()
235   if(args STREQUAL "")
236     message(SEND_ERROR "error: do not know how to extract '${filename}' -- known types are .tar, .tgz and .tar.gz")
237     return()
238   endif()
240   file(WRITE ${script_filename}
241 "# Make file names absolute:
243 get_filename_component(filename \"${filename}\" ABSOLUTE)
244 get_filename_component(tmp \"${tmp}\" ABSOLUTE)
245 get_filename_component(directory \"${directory}\" ABSOLUTE)
247 message(STATUS \"extracting...
248      src='\${filename}'
249      dst='\${directory}'\")
251 # Prepare a space for extracting:
253 set(i 1)
254 while(EXISTS \"\${tmp}/extract\${i}\")
255   math(EXPR i \"\${i} + 1\")
256 endwhile()
257 set(ut_dir \"\${tmp}/extract\${i}\")
258 file(MAKE_DIRECTORY \"\${ut_dir}\")
260 # Extract it:
262 message(STATUS \"extracting... [tar ${args}]\")
263 execute_process(COMMAND \${CMAKE_COMMAND} -E tar ${args} \${filename}
264   WORKING_DIRECTORY \${ut_dir}
265   RESULT_VARIABLE rv)
267 if(NOT rv EQUAL 0)
268   message(STATUS \"extracting... [error clean up]\")
269   file(REMOVE_RECURSE \"\${ut_dir}\")
270   message(FATAL_ERROR \"error: extract of '\${filename}' failed\")
271 endif()
273 # Analyze what came out of the tar file:
275 message(STATUS \"extracting... [analysis]\")
276 file(GLOB contents \"\${ut_dir}/*\")
277 list(LENGTH contents n)
278 if(NOT n EQUAL 1 OR NOT IS_DIRECTORY \"\${contents}\")
279   set(contents \"\${ut_dir}\")
280 endif()
282 # Copy \"the one\" directory to the final directory:
284 message(STATUS \"extracting... [copy]\")
285 file(COPY \"\${contents}/\" DESTINATION \${directory})
287 # Clean up:
289 message(STATUS \"extracting... [clean up]\")
290 file(REMOVE_RECURSE \"\${ut_dir}\")
292 message(STATUS \"extracting... done\")
296 endfunction(_ep_write_extractfile_script)
299 function(_ep_set_directories name)
300   get_property(prefix TARGET ${name} PROPERTY _EP_PREFIX)
301   if(NOT prefix)
302     get_property(prefix DIRECTORY PROPERTY EP_PREFIX)
303     if(NOT prefix)
304       get_property(base DIRECTORY PROPERTY EP_BASE)
305       if(NOT base)
306         set(prefix "${name}-prefix")
307       endif()
308     endif()
309   endif()
310   if(prefix)
311     set(tmp_default "${prefix}/tmp")
312     set(download_default "${prefix}/src")
313     set(source_default "${prefix}/src/${name}")
314     set(binary_default "${prefix}/src/${name}-build")
315     set(stamp_default "${prefix}/src/${name}-stamp")
316     set(install_default "${prefix}")
317   else() # assert(base)
318     set(tmp_default "${base}/tmp/${name}")
319     set(download_default "${base}/Download/${name}")
320     set(source_default "${base}/Source/${name}")
321     set(binary_default "${base}/Build/${name}")
322     set(stamp_default "${base}/Stamp/${name}")
323     set(install_default "${base}/Install/${name}")
324   endif()
325   get_property(build_in_source TARGET ${name} PROPERTY _EP_BUILD_IN_SOURCE)
326   if(build_in_source)
327     get_property(have_binary_dir TARGET ${name} PROPERTY _EP_BINARY_DIR SET)
328     if(have_binary_dir)
329       message(FATAL_ERROR
330         "External project ${name} has both BINARY_DIR and BUILD_IN_SOURCE!")
331     endif()
332   endif()
333   set(top "${CMAKE_CURRENT_BINARY_DIR}")
334   set(places stamp download source binary install tmp)
335   foreach(var ${places})
336     string(TOUPPER "${var}" VAR)
337     get_property(${var}_dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
338     if(NOT ${var}_dir)
339       set(${var}_dir "${${var}_default}")
340     endif()
341     if(NOT IS_ABSOLUTE "${${var}_dir}")
342       get_filename_component(${var}_dir "${top}/${${var}_dir}" ABSOLUTE)
343     endif()
344     set_property(TARGET ${name} PROPERTY _EP_${VAR}_DIR "${${var}_dir}")
345   endforeach()
346   if(build_in_source)
347     get_property(source_dir TARGET ${name} PROPERTY _EP_SOURCE_DIR)
348     set_property(TARGET ${name} PROPERTY _EP_BINARY_DIR "${source_dir}")
349   endif()
351   # Make the directories at CMake configure time *and* add a custom command
352   # to make them at build time. They need to exist at makefile generation
353   # time for Borland make and wmake so that CMake may generate makefiles
354   # with "cd C:\short\paths\with\no\spaces" commands in them.
355   #
356   # Additionally, the add_custom_command is still used in case somebody
357   # removes one of the necessary directories and tries to rebuild without
358   # re-running cmake.
359   foreach(var ${places})
360     string(TOUPPER "${var}" VAR)
361     get_property(dir TARGET ${name} PROPERTY _EP_${VAR}_DIR)
362     file(MAKE_DIRECTORY "${dir}")
363     if(NOT EXISTS "${dir}")
364       message(FATAL_ERROR "dir '${dir}' does not exist after file(MAKE_DIRECTORY)")
365     endif()
366   endforeach()
367 endfunction(_ep_set_directories)
370 function(ep_get name)
371   foreach(var ${ARGN})
372     string(TOUPPER "${var}" VAR)
373     get_property(${var} TARGET ${name} PROPERTY _EP_${VAR})
374     if(NOT ${var})
375       message(FATAL_ERROR "External project \"${name}\" has no ${var}")
376     endif()
377     set(${var} "${${var}}" PARENT_SCOPE)
378   endforeach()
379 endfunction(ep_get)
382 function(_ep_get_configure_command_id name cfg_cmd_id_var)
383   get_target_property(cmd ${name} _EP_CONFIGURE_COMMAND)
385   if(cmd STREQUAL "")
386     # Explicit empty string means no configure step for this project
387     set(${cfg_cmd_id_var} "none" PARENT_SCOPE)
388   else()
389     if(NOT cmd)
390       # Default is "use cmake":
391       set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
392     else()
393       # Otherwise we have to analyze the value:
394       if(cmd MATCHES "^[^;]*/configure")
395         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
396       elseif(cmd MATCHES "^[^;]*/cmake" AND NOT cmd MATCHES ";-[PE];")
397         set(${cfg_cmd_id_var} "cmake" PARENT_SCOPE)
398       elseif(cmd MATCHES "config")
399         set(${cfg_cmd_id_var} "configure" PARENT_SCOPE)
400       else()
401         set(${cfg_cmd_id_var} "unknown:${cmd}" PARENT_SCOPE)
402       endif()
403     endif()
404   endif()
405 endfunction(_ep_get_configure_command_id)
408 function(_ep_get_build_command name step cmd_var)
409   set(cmd "${${cmd_var}}")
410   if(NOT cmd)
411     set(args)
412     _ep_get_configure_command_id(${name} cfg_cmd_id)
413     if(cfg_cmd_id STREQUAL "cmake")
414       # CMake project.  Select build command based on generator.
415       get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
416       if("${cmake_generator}" MATCHES "Make" AND
417           "${cmake_generator}" STREQUAL "${CMAKE_GENERATOR}")
418         # The project uses the same Makefile generator.  Use recursive make.
419         set(cmd "$(MAKE)")
420         if(step STREQUAL "INSTALL")
421           set(args install)
422         endif()
423       else()
424         # Drive the project with "cmake --build".
425         get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
426         if(cmake_command)
427           set(cmd "${cmake_command}")
428         else()
429           set(cmd "${CMAKE_COMMAND}")
430         endif()
431         set(args --build ${binary_dir} --config ${CMAKE_CFG_INTDIR})
432         if(step STREQUAL "INSTALL")
433           list(APPEND args --target install)
434         endif()
435       endif()
436     else() # if(cfg_cmd_id STREQUAL "configure")
437       # Non-CMake project.  Guess "make" and "make install".
438       set(cmd "make")
439       if(step STREQUAL "INSTALL")
440         set(args install)
441       endif()
442     endif()
444     # Use user-specified arguments instead of default arguments, if any.
445     get_property(have_args TARGET ${name} PROPERTY _EP_${step}_ARGS SET)
446     if(have_args)
447       get_target_property(args ${name} _EP_${step}_ARGS)
448     endif()
450     list(APPEND cmd ${args})
451   endif()
453   set(${cmd_var} "${cmd}" PARENT_SCOPE)
454 endfunction(_ep_get_build_command)
457 function(ep_add_step name step)
458   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
459   ep_get(${name} stamp_dir)
461   add_custom_command(APPEND
462     OUTPUT ${cmf_dir}/${name}-complete
463     DEPENDS ${stamp_dir}/${name}-${step}
464     )
465   _ep_parse_arguments(ep_add_step
466                        ${name} _EP_${step}_ "${ARGN}")
468   # Steps depending on this step.
469   get_property(dependers TARGET ${name} PROPERTY _EP_${step}_DEPENDERS)
470   foreach(depender IN LISTS dependers)
471     add_custom_command(APPEND
472       OUTPUT ${stamp_dir}/${name}-${depender}
473       DEPENDS ${stamp_dir}/${name}-${step}
474       )
475   endforeach()
477   # Dependencies on files.
478   get_property(depends TARGET ${name} PROPERTY _EP_${step}_DEPENDS)
480   # Dependencies on steps.
481   get_property(dependees TARGET ${name} PROPERTY _EP_${step}_DEPENDEES)
482   foreach(dependee IN LISTS dependees)
483     list(APPEND depends ${stamp_dir}/${name}-${dependee})
484   endforeach()
486   # The command to run.
487   get_property(command TARGET ${name} PROPERTY _EP_${step}_COMMAND)
488   if(command)
489     set(comment "Performing ${step} step for '${name}'")
490   else()
491     set(comment "No ${step} step for '${name}'")
492   endif()
493   get_property(work_dir TARGET ${name} PROPERTY _EP_${step}_WORKING_DIRECTORY)
495   # Replace list separators.
496   get_property(sep TARGET ${name} PROPERTY _EP_LIST_SEPARATOR)
497   if(sep AND command)
498     string(REPLACE "${sep}" "\\;" command "${command}")
499   endif()
501   # Replace location tags.
502   foreach(var comment command work_dir)
503     if(${var})
504       foreach(dir SOURCE_DIR BINARY_DIR INSTALL_DIR TMP_DIR)
505         get_property(val TARGET ${name} PROPERTY _EP_${dir})
506         string(REPLACE "<${dir}>" "${val}" ${var} "${${var}}")
507       endforeach()
508     endif()
509   endforeach()
511   # Custom comment?
512   get_property(comment_set TARGET ${name} PROPERTY _EP_${step}_COMMENT SET)
513   if(comment_set)
514     get_property(comment TARGET ${name} PROPERTY _EP_${step}_COMMENT)
515   endif()
517   # Run every time?
518   get_property(always TARGET ${name} PROPERTY _EP_${step}_ALWAYS)
519   if(always)
520     set_property(SOURCE ${stamp_dir}/${name}-${step} PROPERTY SYMBOLIC 1)
521     set(touch)
522   else()
523     set(touch ${CMAKE_COMMAND} -E touch ${stamp_dir}/${name}-${step})
524   endif()
526   add_custom_command(
527     OUTPUT ${stamp_dir}/${name}-${step}
528     COMMENT ${comment}
529     COMMAND ${command}
530     COMMAND ${touch}
531     DEPENDS ${depends}
532     WORKING_DIRECTORY ${work_dir}
533     VERBATIM
534     )
535 endfunction(ep_add_step)
538 function(_ep_add_mkdir_command name)
539   ep_get(${name}
540     source_dir binary_dir install_dir stamp_dir download_dir tmp_dir)
541   ep_add_step(${name} mkdir
542     COMMENT "Creating directories for '${name}'"
543     COMMAND ${CMAKE_COMMAND} -E make_directory ${source_dir}
544     COMMAND ${CMAKE_COMMAND} -E make_directory ${binary_dir}
545     COMMAND ${CMAKE_COMMAND} -E make_directory ${install_dir}
546     COMMAND ${CMAKE_COMMAND} -E make_directory ${tmp_dir}
547     COMMAND ${CMAKE_COMMAND} -E make_directory ${stamp_dir}
548     COMMAND ${CMAKE_COMMAND} -E make_directory ${download_dir}
549     )
550 endfunction(_ep_add_mkdir_command)
553 function(_ep_add_download_command name)
554   ep_get(${name} source_dir stamp_dir download_dir tmp_dir)
556   get_property(cmd_set TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND SET)
557   get_property(cmd TARGET ${name} PROPERTY _EP_DOWNLOAD_COMMAND)
558   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
559   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
560   get_property(url TARGET ${name} PROPERTY _EP_URL)
562   # TODO: Perhaps file:// should be copied to download dir before extraction.
563   string(REGEX REPLACE "^file://" "" url "${url}")
565   set(depends)
566   set(comment)
567   set(work_dir)
569   if(cmd_set)
570     set(work_dir ${download_dir})
571   elseif(cvs_repository)
572     find_package(CVS)
573     if(NOT CVS_EXECUTABLE)
574       message(FATAL_ERROR "error: could not find cvs for checkout of ${name}")
575     endif()
577     get_target_property(cvs_module ${name} _EP_CVS_MODULE)
578     if(NOT cvs_module)
579       message(FATAL_ERROR "error: no CVS_MODULE")
580     endif()
582     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
584     set(repository ${cvs_repository})
585     set(module ${cvs_module})
586     set(tag ${cvs_tag})
587     configure_file(
588       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
589       "${stamp_dir}/${name}-cvsinfo.txt"
590       @ONLY
591       )
593     get_filename_component(src_name "${source_dir}" NAME)
594     get_filename_component(work_dir "${source_dir}" PATH)
595     set(comment "Performing download step (CVS checkout) for '${name}'")
596     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q co ${cvs_tag} -d ${src_name} ${cvs_module})
597     list(APPEND depends ${stamp_dir}/${name}-cvsinfo.txt)
598   elseif(svn_repository)
599     find_package(Subversion)
600     if(NOT Subversion_SVN_EXECUTABLE)
601       message(FATAL_ERROR "error: could not find svn for checkout of ${name}")
602     endif()
604     get_property(svn_tag TARGET ${name} PROPERTY _EP_SVN_TAG)
606     set(repository ${svn_repository})
607     set(module)
608     set(tag ${svn_tag})
609     configure_file(
610       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
611       "${stamp_dir}/${name}-svninfo.txt"
612       @ONLY
613       )
615     get_filename_component(src_name "${source_dir}" NAME)
616     get_filename_component(work_dir "${source_dir}" PATH)
617     set(comment "Performing download step (SVN checkout) for '${name}'")
618     set(cmd ${Subversion_SVN_EXECUTABLE} co ${svn_repository} ${svn_tag} ${src_name})
619     list(APPEND depends ${stamp_dir}/${name}-svninfo.txt)
620   elseif(url)
621     get_filename_component(work_dir "${source_dir}" PATH)
622     set(repository "external project URL")
623     set(module "${url}")
624     set(tag "")
625     configure_file(
626       "${CMAKE_ROOT}/Modules/RepositoryInfo.txt.in"
627       "${stamp_dir}/${name}-urlinfo.txt"
628       @ONLY
629       )
630     list(APPEND depends ${stamp_dir}/${name}-urlinfo.txt)
631     if(IS_DIRECTORY "${url}")
632       get_filename_component(abs_dir "${url}" ABSOLUTE)
633       set(comment "Performing download step (DIR copy) for '${name}'")
634       set(cmd   ${CMAKE_COMMAND} -E remove_directory ${source_dir}
635         COMMAND ${CMAKE_COMMAND} -E copy_directory ${abs_dir} ${source_dir})
636     else()
637       if("${url}" MATCHES "^[a-z]+://")
638         # TODO: Should download and extraction be different steps?
639         string(REGEX MATCH "[^/]*$" fname "${url}")
640         if(NOT "${fname}" MATCHES "\\.(tar|tgz|tar\\.gz)$")
641           message(FATAL_ERROR "Could not extract tarball filename from url:\n  ${url}")
642         endif()
643         set(file ${download_dir}/${fname})
644         _ep_write_downloadfile_script("${stamp_dir}/download-${name}.cmake" "${url}" "${file}" "")
645         set(cmd ${CMAKE_COMMAND} -P ${stamp_dir}/download-${name}.cmake
646           COMMAND)
647         set(comment "Performing download step (download and extract) for '${name}'")
648       else()
649         set(file "${url}")
650         set(comment "Performing download step (extract) for '${name}'")
651       endif()
652       # TODO: Support other archive formats.
653       _ep_write_extractfile_script("${stamp_dir}/extract-${name}.cmake" "${file}" "${tmp_dir}" "${source_dir}")
654       list(APPEND cmd ${CMAKE_COMMAND} -P ${stamp_dir}/extract-${name}.cmake)
655     endif()
656   else()
657     message(SEND_ERROR "error: no download info for '${name}'")
658   endif()
660   ep_add_step(${name} download
661     COMMENT ${comment}
662     COMMAND ${cmd}
663     WORKING_DIRECTORY ${work_dir}
664     DEPENDS ${depends}
665     DEPENDEES mkdir
666     )
667 endfunction(_ep_add_download_command)
670 function(_ep_add_update_command name)
671   ep_get(${name} source_dir)
673   get_property(cmd_set TARGET ${name} PROPERTY _EP_UPDATE_COMMAND SET)
674   get_property(cmd TARGET ${name} PROPERTY _EP_UPDATE_COMMAND)
675   get_property(cvs_repository TARGET ${name} PROPERTY _EP_CVS_REPOSITORY)
676   get_property(svn_repository TARGET ${name} PROPERTY _EP_SVN_REPOSITORY)
678   set(work_dir)
679   set(comment)
680   set(always)
682   if(cmd_set)
683     set(work_dir ${source_dir})
684   elseif(cvs_repository)
685     if(NOT CVS_EXECUTABLE)
686       message(FATAL_ERROR "error: could not find cvs for update of ${name}")
687     endif()
688     set(work_dir ${source_dir})
689     set(comment "Performing update step (CVS update) for '${name}'")
690     get_property(cvs_tag TARGET ${name} PROPERTY _EP_CVS_TAG)
691     set(cmd ${CVS_EXECUTABLE} -d ${cvs_repository} -q up -dP ${cvs_tag})
692     set(always 1)
693   elseif(svn_repository)
694     if(NOT Subversion_SVN_EXECUTABLE)
695       message(FATAL_ERROR "error: could not find svn for update of ${name}")
696     endif()
697     set(work_dir ${source_dir})
698     set(comment "Performing update step (SVN update) for '${name}'")
699     get_property(svn_tag TARGET ${name} PROPERTY _EP_SVN_TAG)
700     set(cmd ${Subversion_SVN_EXECUTABLE} up ${svn_tag})
701     set(always 1)
702   endif()
704   ep_add_step(${name} update
705     COMMENT ${comment}
706     COMMAND ${cmd}
707     ALWAYS ${always}
708     WORKING_DIRECTORY ${work_dir}
709     DEPENDEES download
710     )
711 endfunction(_ep_add_update_command)
714 function(_ep_add_patch_command name)
715   ep_get(${name} source_dir)
717   get_property(cmd_set TARGET ${name} PROPERTY _EP_PATCH_COMMAND SET)
718   get_property(cmd TARGET ${name} PROPERTY _EP_PATCH_COMMAND)
720   set(work_dir)
722   if(cmd_set)
723     set(work_dir ${source_dir})
724   endif()
726   ep_add_step(${name} patch
727     COMMAND ${cmd}
728     WORKING_DIRECTORY ${work_dir}
729     DEPENDEES download
730     )
731 endfunction(_ep_add_patch_command)
734 # TODO: Make sure external projects use the proper compiler
735 function(_ep_add_configure_command name)
736   ep_get(${name} source_dir binary_dir)
738   # Depend on other external projects (file-level).
739   set(file_deps)
740   get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
741   foreach(dep IN LISTS deps)
742     get_property(dep_stamp_dir TARGET ${dep} PROPERTY _EP_STAMP_DIR)
743     list(APPEND file_deps ${dep_stamp_dir}/${dep}-done)
744   endforeach()
746   get_property(cmd_set TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND SET)
747   if(cmd_set)
748     get_property(cmd TARGET ${name} PROPERTY _EP_CONFIGURE_COMMAND)
749   else()
750     get_target_property(cmake_command ${name} _EP_CMAKE_COMMAND)
751     if(cmake_command)
752       set(cmd "${cmake_command}")
753     else()
754       set(cmd "${CMAKE_COMMAND}")
755     endif()
757     get_property(cmake_args TARGET ${name} PROPERTY _EP_CMAKE_ARGS)
758     list(APPEND cmd ${cmake_args})
760     get_target_property(cmake_generator ${name} _EP_CMAKE_GENERATOR)
761     if(cmake_generator)
762       list(APPEND cmd "-G${cmake_generator}" "${source_dir}")
763     endif()
764   endif()
766   ep_add_step(${name} configure
767     COMMAND ${cmd}
768     WORKING_DIRECTORY ${binary_dir}
769     DEPENDEES update patch
770     DEPENDS ${file_deps}
771     )
772 endfunction(_ep_add_configure_command)
775 function(_ep_add_build_command name)
776   ep_get(${name} binary_dir)
778   get_property(cmd_set TARGET ${name} PROPERTY _EP_BUILD_COMMAND SET)
779   if(cmd_set)
780     get_property(cmd TARGET ${name} PROPERTY _EP_BUILD_COMMAND)
781   else()
782     _ep_get_build_command(${name} BUILD cmd)
783   endif()
784   ep_add_step(${name} build
785     COMMAND ${cmd}
786     WORKING_DIRECTORY ${binary_dir}
787     DEPENDEES configure
788     )
789 endfunction(_ep_add_build_command)
792 function(_ep_add_install_command name)
793   ep_get(${name} binary_dir)
795   get_property(cmd_set TARGET ${name} PROPERTY _EP_INSTALL_COMMAND SET)
796   if(cmd_set)
797     get_property(cmd TARGET ${name} PROPERTY _EP_INSTALL_COMMAND)
798   else()
799     _ep_get_build_command(${name} INSTALL cmd)
800   endif()
801   ep_add_step(${name} install
802     COMMAND ${cmd}
803     WORKING_DIRECTORY ${binary_dir}
804     DEPENDEES build
805     )
806 endfunction(_ep_add_install_command)
809 function(ep_add name)
810   # Add a custom target for the external project.
811   set(cmf_dir ${CMAKE_CURRENT_BINARY_DIR}/CMakeFiles)
812   add_custom_target(${name} ALL DEPENDS ${cmf_dir}/${name}-complete)
813   set_property(TARGET ${name} PROPERTY _EP_IS_EXTERNAL_PROJECT 1)
814   _ep_parse_arguments(ep_add ${name} _EP_ "${ARGN}")
815   _ep_set_directories(${name})
816   ep_get(${name} stamp_dir)
818   # The 'complete' step depends on all other steps and creates a
819   # 'done' mark.  A dependent external project's 'configure' step
820   # depends on the 'done' mark so that it rebuilds when this project
821   # rebuilds.  It is important that 'done' is not the output of any
822   # custom command so that CMake does not propagate build rules to
823   # other external project targets.
824   add_custom_command(
825     OUTPUT ${cmf_dir}/${name}-complete
826     COMMENT "Completed '${name}'"
827     COMMAND ${CMAKE_COMMAND} -E touch ${cmf_dir}/${name}-complete
828     COMMAND ${CMAKE_COMMAND} -E touch ${stamp_dir}/${name}-done
829     DEPENDS ${stamp_dir}/${name}-install
830     VERBATIM
831     )
834   # Depend on other external projects (target-level).
835   get_property(deps TARGET ${name} PROPERTY _EP_DEPENDS)
836   foreach(arg IN LISTS deps)
837     add_dependencies(${name} ${arg})
838   endforeach()
840   # Set up custom build steps based on the target properties.
841   # Each step depends on the previous one.
842   #
843   # The target depends on the output of the final step.
844   # (Already set up above in the DEPENDS of the add_custom_target command.)
845   #
846   _ep_add_mkdir_command(${name})
847   _ep_add_download_command(${name})
848   _ep_add_update_command(${name})
849   _ep_add_patch_command(${name})
850   _ep_add_configure_command(${name})
851   _ep_add_build_command(${name})
852   _ep_add_install_command(${name})
853 endfunction(ep_add)