CMake FAQ

From KitwarePublic
Revision as of 05:30, 15 June 2012 by 199.106.103.56 (talk) (Undo revision 47836 by 12.31.248.67 (talk))
Jump to navigationJump to search
Hello! gdeddfe interesting gdeddfe site! I'm really like it! Very, very gdeddfe good!

Very nice site!

Hello! aeekede interesting aeekede site! I'm really like it! Very, very aeekede good!

Very nice site!

Writing FindXXX.cmake files

What are the rules to write a FindXXX.cmake file?

Let's follow the instructions and the advices in the Modules/readme.txt [1] file located in the CVS repository.

Why does find_library look in system directories before its PATHS option?

The code in question is often of the form

 find_library(FOO_LIBRARY NAMES foo PATHS /opt/foo/lib)

CMake will find "/usr/lib/libfoo.so" instead of "/opt/foo/lib/libfoo.so" if both exist. The reason is that /opt/foo/lib is a hard-coded guess of the location. The documentation of find_library specifies the search order. User, project, and system configuration variables are always more local than hard-coded guesses and should override them, so the PATHS option is used last.

Some find-modules compute probable locations based on other information available from the system such as a project-specific environment variable. The HINTS option (CMake 2.6 and higher) takes precedence over system directories specifically for this case:

 file(TO_CMAKE_PATH "$ENV{FOO_LIB_DIR}" FOO_LIB_DIR)
 find_library(FOO_LIBRARY NAMES foo HINTS ${FOO_LIB_DIR})

CMake will find "$ENV{FOO_LIB_DIR}/libfoo.so" before "/usr/lib/libfoo.so".

Finding and using external packages

How do I use CMake to generate SWIG wrapper libraries?

CMake version 2 includes a module that supports the generation of SWIG wrapper libraries. The SWIG package defines the following macros: SWIG_ADD_MODULE and SWIG_LINK_LIBRARIES.

# This example shows how to use python
# Currently these languages have been tested:
#  perl tcl ruby php4 pike

FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})

FIND_PACKAGE(PythonLibs)
INCLUDE_DIRECTORIES(${PYTHON_INCLUDE_PATH})

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SWIG_FLAGS "")

SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(example python
  example.i example.cxx)
SWIG_LINK_LIBRARIES(example ${PYTHON_LIBRARIES})

# This example shows how to use tcl
PROJECT(TCL_WRAP)
SET (	MODULE_NAME		project	)
SET (	INTERFACE_FILES		project.i)
SET (	SRC_FILES		Vertex.h Vertex.cxx Shapes.h Shapes.cxx )

FIND_PACKAGE(SWIG REQUIRED)
INCLUDE(${SWIG_USE_FILE})

# Look for TCL
INCLUDE_DIRECTORIES(${TCL_INCLUDE_PATH})

FIND_LIBRARY(TCL_LIBRARY NAMES tcl tcl84 tcl83 tcl82 tcl80
				PATHS /usr/lib /usr/local/lib)
IF (TCL_LIBRARY)
	TARGET_ADD_LIBRARY (${MODULE_NAME} TCL_LIBRARY)
ENDIF (TCL_LIBRARY)

INCLUDE_DIRECTORIES(${CMAKE_CURRENT_SOURCE_DIR})

SET(CMAKE_SWIG_FLAGS "-c++")

SET_SOURCE_FILES_PROPERTIES(${INTERFACE_FILES} PROPERTIES CPLUSPLUS ON)
SET_SOURCE_FILES_PROPERTIES(${INTERFACE_FILES} PROPERTIES CMAKE_SWIG_FLAGS "-includeall")
SWIG_ADD_MODULE(${MODULE_NAME} tcl ${INTERFACE_FILES} ${SRC_FILES})
SWIG_LINK_LIBRARIES(${MODULE_NAME} ${TCL_LIBRARIES})

If you get errors indicating that C and C++ include files cannot be found, like,

Error: Unable to find 'string.h'
Error: Unable to find 'time.h'
Error: Unable to find 'string'
Error: Unable to find 'functional'
Error: Unable to find 'utility'
Error: Unable to find 'limits.h'
Error: Unable to find 'fstream'
Error: Unable to find 'sys/times.h'
Error: Unable to find 'unistd.h'
Error: Unable to find 'malloc.h'
   ...

try setting the -includeall property on fewer source files:

# Try doing this on fewer files
SET_SOURCE_FILES_PROPERTIES(example.i PROPERTIES SWIG_FLAGS "-includeall")

In particular, you may need -includeall only on the top-level .i files.

How do I use CMake to build LaTeX documents?

Use the following approach. Note that you have to set LATEX_COMPILE to LaTeX executable, DVIPDF_COMPILE to dvi to pdf converter. Also, the LaTeX source is TDocument.tex and the result is called TDocument.pdf. Note that this uses commands in CMake version 1.8 or later.

PROJECT(Document)
IF(LATEX_COMPILE)
  ADD_CUSTOM_COMMAND(
    OUTPUT    ${Document_BINARY_DIR}/TDocument.dvi
    DEPENDS   ${Document_BINARY_DIR}/TDocument.tex
    COMMAND   ${LATEX_COMPILE}  
    ARGS      ${Document_SOURCE_DIR}/TDocument.tex 
    )
ENDIF(LATEX_COMPILE)

IF(DVIPDF_COMPILE)
  ADD_CUSTOM_COMMAND(
    OUTPUT    ${Document_BINARY_DIR}/TDocument.pdf
    DEPENDS   ${Document_BINARY_DIR}/TDocument.dvi 
    COMMAND   ${DVIPDF_COMPILE}
    ARGS      ${Document_SOURCE_DIR}/TDocument.dvi
    )
ENDIF(DVIPDF_COMPILE)
ADD_CUSTOM_TARGET(LaTeXDocument ALL echo
  DEPENDS ${Document_BINARY_DIR}/TDocument.pdf
  )

The following uses commands in CMake version 2.0 and later

PROJECT(Document)
# 
# Find LaTeX
#
FIND_PACKAGE(LATEX)
IF(LATEX_COMPILER)
  ADD_CUSTOM_COMMAND( 
    OUTPUT    ${Document_BINARY_DIR}/TDocument.dvi
    COMMAND   ${LATEX_COMPILER}
    ARGS      ${Document_SOURCE_DIR}/TDocument.tex
    DEPENDS   ${Document_SOURCE_DIR}/TDocument.tex
    COMMENT   "Tex2dvi"
  )
  IF(DVIPS_CONVERTER)
    ADD_CUSTOM_COMMAND( 
      OUTPUT    ${Document_BINARY_DIR}/TDocument.ps
      COMMAND   ${DVIPS_CONVERTER}
      ARGS      ${Document_BINARY_DIR}/TDocument.dvi
                -o ${Document_BINARY_DIR}/TDocument.ps
      DEPENDS   ${Document_BINARY_DIR}/TDocument.dvi
      COMMENT   "dvi2ps"
   )

 IF(PS2PDF_CONVERTER)
    ADD_CUSTOM_COMMAND( 
      OUTPUT    ${Document_BINARY_DIR}/TDocument.pdf
      COMMAND   ${PS2PDF_CONVERTER}
      ARGS      ${Document_BINARY_DIR}/TDocument.ps
      DEPENDS   ${Document_BINARY_DIR}/TDocument.ps
      COMMENT   "ps2pdf"
    )
    ADD_CUSTOM_TARGET(LaTeXDocument ALL echo
      DEPENDS   ${Document_BINARY_DIR}/TDocument.pdf
    )
    ENDIF(PS2PDF_CONVERTER)
  ENDIF(DVIPS_CONVERTER)
ENDIF(LATEX_COMPILER)

How do I get LaTeX references to be correct?

When your latex document contains references (e.g. \ref{...} command) you get to run two passes of latex. In the most general case, i.e. when additionally your document uses a bibtex bibliography, you shall need three passes of latex (and one pass of bibtex):

  1. latex (first pass: for bibtex to have an .aux file)
  2. bibtex (for generating the .bbl file)
  3. latex (second pass)
  4. latex (third pass)

The following code snippet illustrates how you can "pervert" the bibtex and latex generated auxilary files (.aux, .log, .dvi, .bbl...) to create an "artificial" set of CMake dependencies. The side-effect of those dependencies should hopefully be the above described sequence of calls to latex and bibtex

ADD_CUSTOM_COMMAND(
  OUTPUT    ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.aux
  DEPENDS   ${CMAKE_CURRENT_SOURCE_DIR}/UsersManual.tex
  COMMAND   ${LATEX_COMPILER}
  ARGS      -interaction=batchmode ${CMAKE_CURRENT_BINARY_DIR}/UsersManual
  COMMENT   "Latex (first pass)"
  )

ADD_CUSTOM_COMMAND(
  OUTPUT    ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.bbl
  DEPENDS   ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.aux
  COMMAND   ${BIBTEX_COMPILER}
  ARGS      -terse ${CMAKE_CURRENT_BINARY_DIR}/UsersManual
  COMMENT   "Bibtex"
  )

ADD_CUSTOM_COMMAND(
  OUTPUT    ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.dvi
  DEPENDS   ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.bbl
  COMMAND   ${LATEX_COMPILER}
  ARGS      -interaction=batchmode ${CMAKE_CURRENT_BINARY_DIR}/UsersManual
  COMMENT   "Latex (second pass)"
  )

ADD_CUSTOM_COMMAND(
  OUTPUT    ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.log
  DEPENDS   ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.bbl
            ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.dvi
  COMMAND   ${LATEX_COMPILER}
  ARGS      -interaction=batchmode ${CMAKE_CURRENT_BINARY_DIR}/UsersManual
  COMMENT   "Latex (third pass)"
  )
# Eventually trigger the whole process
ADD_CUSTOM_TARGET(LaTeXDocument ALL echo
   DEPENDS   ${CMAKE_CURRENT_BINARY_DIR}/UsersManual.log
   )

How can I set TEXINPUTS for a LaTeX compilation?

First note that most often you can avoid using TEXINPUTS by copying all the necessary files (.tex source file and included graphic files e.g. .eps files) from your PROJECT_SOURCE_DIR hirarchy to your PROJECT_BINARY_DIR subdir [refer to CONFIGURE_FILE with the COPYONLY flag set for copying files]. Since by default latex uses the current working directory as value for TEXINPUTS you should be all set. As expected, this trick is quick AND dirty since your concerned PROJECT_BINARY_DIR subdir now contains files that are NOT generated by CMake (in the sense that those files are not the result of a system command but were merely duplicated)...

If you consider it is cleaner or easier to define a TEXINPUTS environment variable [the latex command probably misses a -I flag] you can find an example in the InsightDocuments cvs archive (refer to the section "cvs access" near the bottom of Kitware's ITK download page) or use google with keywords "ITK_TEXINPUTS CONFIGURE_FILE". Look at InsightDocuments/CourseWare/Training/Vis2003/Latex/CMakeLists.txt and search for e.g. "LaTeXWrapper.sh.in".

Roughly the mechanism goes:

  • SET ITK_TEXINPUTS with the desired TEXINPUTS
  • CONFIGURE_FILE "InsightDocuments/CourseWare/Training/Vis2003/LaTeXWrapper.sh.in" which generates an sh shell script setting the shell variable TEXINPUTS prior to running the latex command
  • use ADD_CUSTOM_COMMAND to invoke this shell script

This very example is Win32 portable (except that LaTeXWrapper.bat.in generates a .bat shell script)

Library questions

Can I build both shared and static libraries with one ADD_LIBRARY command?

No. Each library you build must have a unique target name, i.e. the "libname" field of the ADD_LIBRARY command. That way, CMake can track dependencies separately for each library. Libraries can have the same OUTPUT_NAME, see the SET_TARGET_PROPERTIES command, but this is not the default.

Does that mean I have to build all my library objects twice, once for shared and once for static?! I don't like that!

In practice, most libraries have different defines and compiler flags for the shared vs. static cases. So you would have to build all your library objects twice anyways. However, if you happen to have exactly the same defines and compiler flags for the shared vs. static cases...

...if you're using Linux and a GCC-style linker, you could do the following. Note that for this to work correctly on linux, the zzSTATIC source files should have been compiled with "-fPIC" to ensure they will work in a shared library.

 IF(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_COMPILER_IS_GNUCC)
   ADD_LIBRARY(zzSTATIC STATIC -fPIC)
   ADD_LIBRARY(zzDYNAMIC SHARED)
   TARGET_LINK_LIBRARIES(zzDYNAMIC -Wl,-whole-archive zzSTATIC -Wl,-no-whole-archive)
 ENDIF(CMAKE_SYSTEM_NAME STREQUAL "Linux" AND CMAKE_COMPILER_IS_GNUCC)

...if you want a cross-platform approach that works on all compilers, not just GCC or Linux, you could extract the locations of previously built object files and insert them directly into the libraries that need them. This is documented in CMake Feature Request #5155: standard way to locate object files. Unfortunately this approach relies on CMake's internal implementation, and that implementation could change in the future, breaking your code.

How do I make my shared and static libraries have the same root name, but different suffixes?

Set the OUTPUT_NAME of your shared and static libraries to the same thing.

 ADD_LIBRARY(foo SHARED ${foo_sources})
 ADD_LIBRARY(foo-static STATIC ${foo_sources})
 # The library target "foo" already has a default OUTPUT_NAME of "foo", so we don't need to change it.
 # The library target "foo-static" has a default OUTPUT_NAME of "foo-static", so change it.
 SET_TARGET_PROPERTIES(foo-static PROPERTIES OUTPUT_NAME "foo")
 # Now the library target "foo-static" will be named "foo.lib" with MS tools.
 # This conflicts with the "foo.lib" import library corresponding to "foo.dll",
 # so we add a "lib" prefix (which is default on other platforms anyway):
 SET_TARGET_PROPERTIES(foo-static PROPERTIES PREFIX "lib")

One more detail is needed with CMake 2.6.x and lower (but not CMake 2.8 or higher). If you are building your shared and static libraries in the same directory, you will also need the following to keep your shared and static libraries from clobbering each other during the build.

 # Help CMake 2.6.x and lower (not necessary for 2.8 and above, but doesn't hurt):
 SET_TARGET_PROPERTIES(foo PROPERTIES CLEAN_DIRECT_OUTPUT 1)
 SET_TARGET_PROPERTIES(foo-static PROPERTIES CLEAN_DIRECT_OUTPUT 1)

How do I rename a library after it has already been built?

You don't rename it. It's been built! Its name is whatever CMakeLists.txt says it's supposed to be.

Perhaps you want to copy the library to a different name. But, are you sure that's what you want to do? You could just change the name in your ADD_LIBRARY command or change its OUTPUT_NAME property using SET_TARGET_PROPERTY(). If you really really want to copy the library to a different name, try:

 GET_TARGET_PROPERTY(LIB_NAME Foo LOCATION)
 GET_TARGET_PROPERTY(Bar_prefix Foo PREFIX)
 GET_TARGET_PROPERTY(Bar_suffix Foo SUFFIX)
 SET(NEW_LIB_NAME ${Bar_prefix}Bar${Bar_suffix})
 
 ADD_CUSTOM_COMMAND(
   TARGET Foo
   POST_BUILD
   COMMAND ${CMAKE_COMMAND} -E copy ${LIB_NAME} ${NEW_LIB_NAME}
 )

On Windows you may also want to copy the .dll import lib, using the same approach as above, but with IMPORT_PREFIX and IMPORT_SUFFIX. Problem: LOCATION only refers to 1 file, the .dll. What is a simple way to get the location of the import lib? Could provide a complicated way, but that's annoying.

Does CMake support "convenience" libraries?

No. CMake does not currently support convenience libraries. A "convenience" library, as GNU libtool calls it, is an archive of objects to be mixed into other libraries. Other libraries "link" to the convenience library, but the convenience library does not export any symbols; GNU libtool never installs the convenience library; no programs ever link to the convenience library.

This does not mean that a project using convenience libraries cannot be converted to CMake. Instead the source files may be listed in each target that needs them. They will be built for each target separately using all the preprocessor definitions and flags configured for that target.

Why are libraries linked to my shared library included when something links to it?

This question arises when one has a library B which links to some library A. When a third target, say C, links to B, CMake will automatically include C to A also. When the libraries are static, then this is always necessary. When the libraries are shared, this is the default behavior provided by CMake. CMake 2.6 and above provide the target property "LINK_INTERFACE_LIBRARIES" to specify the libraries that should be transitively included in the link by CMake. CMake 2.4 and below do not support the property.

Something like the following will work in CMake 2.6 and above:

  set_target_properties(mylibrary
      PROPERTIES
      LINK_INTERFACE_LIBRARIES ""
  )

CMake dependency scanner

CMake does not preprocess source files while scanning dependencies. Code like

 #if 0
 # include "bla.h"
 #endif

will result in a dependency on "bla.h". This sometimes leads to source files recompiling unnecessarily but will not break the build.

Installation questions

Does CMake's "make install" support DESTDIR?

Yes, especially when the build-system generator uses CMake's builtin support for installing files: Simply define the DESTDIR environment variable during installation and CMake will treat that value as the root of the file system for all installation paths; naturally, the DESTDIR path must be absolute.

For example, if the Makefile generator is used, then all of the following are example usages of DESTDIR (perhaps assuming the bash shell for the last 2):

(1) make install DESTDIR="/some/absolute/path"
(2) make DESTDIR="/some/absolute/path" install
(3) DESTDIR="/some/absolute/path" make install
(4) export DESTDIR="/some/absolute/path
    make install

Can I do "make uninstall" with CMake?

By default, CMake does not provide the "make uninstall" target, so you cannot do this. We do not want "make uninstall" to remove useful files from the system.

If you want an "uninstall" target in your project, then nobody prevents you from providing one. You need to delete the files listed in install_manifest.txt file. Here is how to do it. First create file cmake_uninstall.cmake.in in the top-level directory of the project:

if (NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")
    message(FATAL_ERROR "Cannot find install manifest: \"@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt\"")
endif(NOT EXISTS "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt")

file(READ "@CMAKE_CURRENT_BINARY_DIR@/install_manifest.txt" files)
string(REGEX REPLACE "\n" ";" files "${files}")
list(REVERSE files)
foreach (file ${files})
    message(STATUS "Uninstalling \"$ENV{DESTDIR}${file}\"")
    if (EXISTS "$ENV{DESTDIR}${file}")
        execute_process(
            COMMAND @CMAKE_COMMAND@ -E remove "$ENV{DESTDIR}${file}"
            OUTPUT_VARIABLE rm_out
            RESULT_VARIABLE rm_retval
        )
        if(NOT ${rm_retval} EQUAL 0)
            message(FATAL_ERROR "Problem when removing \"$ENV{DESTDIR}${file}\"")
        endif (NOT ${rm_retval} EQUAL 0)
    else (EXISTS "$ENV{DESTDIR}${file}")
        message(STATUS "File \"$ENV{DESTDIR}${file}\" does not exist.")
    endif (EXISTS "$ENV{DESTDIR}${file}")
endforeach(file)

Then in the top-level CMakeLists.txt add the following logic:

# uninstall target
configure_file(
    "${CMAKE_CURRENT_SOURCE_DIR}/cmake_uninstall.cmake.in"
    "${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake"
    IMMEDIATE @ONLY)

add_custom_target(uninstall
    COMMAND ${CMAKE_COMMAND} -P ${CMAKE_CURRENT_BINARY_DIR}/cmake_uninstall.cmake)

Now you will have an "uninstall" target at the top-level directory of your build tree.

Instead of creating an "uninstall" target, Unix users could enter this command in the shell:

 xargs rm < install_manifest.txt

Distribution questions

Where is "make dist"?

CMake doesn't create a "make dist" target.

What is the best way to distribute source code or binaries for a cmake-based project?

For creating source or binary packages there is now CPack coming with CMake, see the documentation.

Of course you can also use any other ways to create packages.

Platform-specific questions

How do I build universal binaries on Mac OS X?

Before running CMake with an empty build tree, set the CMAKE_OSX_ARCHITECTURES environment variable. It should be set to contain a ; separated list of architectures that you want in the binary. For example, for 32-bit PowerPC and Intel you would do this:

CMAKE_OSX_ARCHITECTURES=ppc;i386

If you wish to build both as 32 and 64 bit, do this:

CMAKE_OSX_ARCHITECTURES=ppc;i386;ppc64;x86_64

You can also set the same named CMake cache variable on an existing binary tree. This works with both makefiles and the Xcode generator.

In addition, you can also set the CMAKE_OSX_SYSROOT variable to point to the sysroot (aka Mac OS SDK) to be used. CMake will attempt to pick one on your system, but it can be changed in the cache or via an environment variable before running CMake. The 10.4u SDK or later must be used to create a Universal Binary.

Universal Binaries are essentially cross compilation and so you should avoid using TRY_RUN, especially for things like testing endianess or variable size because the result will only be correct for one architecture.

Lastly, note that CTest is only able to test one architecture. See bug 6157.

How can I apply resources on Mac OS X automatically?

Using ADD_CUSTOM_COMMAND. For example, let's say you are creating executable MyExecutable, which needs the resources file Carbon.r. All you do is add a custom rule which is executed after the executable is linked:

 ADD_EXECUTABLE(MyExecutable ${MyExecutable_SRCS})
 GET_TARGET_PROPERTY(MyExecutable_PATH MyExecutable LOCATION)

 IF(APPLE)
   FIND_PROGRAM(APPLE_RESOURCE Rez /Developer/Tools)
   IF(APPLE_RESOURCE)
     ADD_CUSTOM_COMMAND(TARGET MyExecutable POST_BUILD
                        COMMAND ${APPLE_RESOURCE} Carbon.r -o ${MyExecutable_PATH})
   ENDIF(APPLE_RESOURCE)
 ENDIF(APPLE)

This will execute:

/Developer/Tools/Rez Carbon.r -o /binary/path/MyExecutable

after MyExecutable is linked.

'Rez' may be located elsewhere on disk, depending on the version of Mac OS X and Xcode. You can use 'which Rez' in Terminal to find it's full path.

Why does FIND_LIBRARY not find .DLL libraries under WIN32?

For those who come from a Unix background to MS Windows:

You never link directly to the .dll, you have to link against the import library .lib for the .dll.

Linking against dynamic libraries (.dll under Windows) is quite different from linking against ELF shared objects (.so) under platforms like Linux or NetBSD. In Windows, there are two types of library, a static library and an import library (both confusingly use the .lib extension, however). In Windows, when you build an import library (A.lib) you will get a corresponding (A.dll) that you only need at runtime. At compile time you will need the import library.

Conclusion: There is no need to find a .dll for linking. You only need to find the .lib import library.

Some more details can be found here: [2].

Why am I getting a linker error to _mainCRTStartup under WIN32?

Your program is a GUI application using WinMain (/subsystem:windows) and not a console application using main. You have to use the WIN32 option with the ADD_EXECUTABLE command.

ADD_EXECUTABLE(exename WIN32 source1 source2 ... sourceN)

The second argument to ADD_EXECUTABLE can be WIN32. This indicates that the executable, when compiled on Windows, is a Windows app (using WinMain) and not a console app (using main). Please note that on Unix platforms, CMake ignores the WIN32 and the compiler will use "main" in any case.

Why do I get this error: nafxcwd.lib(appcore.obj) : error LNK2001: unresolved external symbol ___argv

This is because the application is using both the static and dll versions of the MFC library. To fix the problem, you can do the following:

SET(CMAKE_MFC_FLAG 2)     # force the IDE to use static MFC
ADD_DEFINITIONS(-D_AFXDLL) # make sure if afx.h is included the dll MFC is used

How to use MFC with CMake

To use MFC, the CMAKE_MFC_FLAG variable must be set as follows:

0: Use Standard Windows Libraries
1: Use MFC in a Static Library
2: Use MFC in a Shared DLL 

This can be set in a CMakeLists.txt file and will enable MFC in the application. It should be set to 1 or 2. This is used in visual studio 6 and 7 project files. The CMakeSetup dialog uses MFC and the CMakeLists.txt looks like this:

ADD_DEFINITIONS(-D_AFXDLL)
SET(CMAKE_MFC_FLAG 2) 
ADD_EXECUTABLE(CMakeSetup WIN32 ${SRCS})

Note that visual studio 9 project files do not appear to work with CMAKE_MFC_FLAG 1; this may be related to bug 7056.

In order to use MFC with UNICODE, you must also specify the entry point wWinMainCRTStartup. For example:

set(CMAKE_MFC_FLAG 2)
set_target_properties(MyApp PROPERTIES
    COMPILE_DEFINITIONS _AFXDLL,_UNICODE,UNICODE,_BIND_TO_CURRENT_CRT_VERSION,_BIND_TO_CURRENT_MFC_VERSION
    LINK_FLAGS "/ENTRY:\"wWinMainCRTStartup\"")

See this article as to why _BIND_TO_CURRENT_CRT_VERSION and _BIND_TO_CURRENT_MFC_VERSION are necessary for Visual Studio 2008 SP1.

How To Put Files in Folders in Visual Studio Projects

The Visual Studio IDE supports putting files into folders. CMake can be used to put files in folders with the SOURCE_GROUP command.

 SOURCE_GROUP(name [REGULAR_EXPRESSION regex] [FILES src1 src2 ...])

Defines a group into which sources will be placed in project files. This is mainly used to setup file tabs in Visual Studio. Any file whose name is listed or matches the regular expression will be placed in this group provided the source file is being passed to ADD_EXECUTABLE or ADD_LIBRARY.

 For example:
 SOURCE_GROUP(FooFiles FILES foo.cxx)
 SOURCE_GROUP(BarFiles FILES bar.cxx)
 ADD_LIBRARY(foo foo.cxx bar.cxx)

In the event a file matches multiple groups, the LAST group that explicitly lists the file will be favored, if any. If no group explicitly lists the file, the LAST group whose regular expression matches the file will be favored. For backwards compatibility this command is also supports the format SOURCE_GROUP(name regex).

As a convenience to developers CMake automatically adds standard header files to a "Header Files" folder and standard source files to a "Source Files" folder for Visual Studio Projects. This can be overridden via the SOURCE_GROUP method documented above.

How to create Visual Studio 6 Projects that contain only a single build type

For Visual Studio.NET (version 7.0 and above) it is possible to set the CMAKE_CONFIGURATION_TYPES variable to the build type(s) (Debug/Release/...) that you want. This does not work for Visual Studio 6. There is however a way to achieve this. To create your own set of configurations:

  1. Create a directory in which you copy the files *.dsptemplate and CMakeVisualStudio6Configurations.cmake from CMake's Templates directory.
  2. Edit the .cmake file and change the SET(CMAKE_CONFIGURATION_TYPES ...) line to set the build types that you want in your set.
  3. Edit the *Header.dsptemplate files to contain only the configuration types you want in your set.
  4. In your CMakeLists.txt file, set the MSPROJECT_TEMPLATE_DIRECTORY to the directory that you created.


That's it. Run CMake and your new configuration files will be created.

Note: Editing the *Header.dsptemplates files should be done very carefully. Here are some guidelines:

- You MUST remove the targets that you do not want in your set at the bottom of the file (e.g. '# Name "OUTPUT_LIBNAME - Win32 MinSizeRel"') - You can remove the '!IF "$(CFG)" == ...' until '!ELSEIF "$(CFG)" == ...' or '!ELSEIF "$(CFG)" == ...' until '!ENDIF' lines for the configurations you do not want. Make sure that the resulting code still starts with '!IF ...' and ends with '!ENDIF' with any number of '!ELSEIF' sections in between. If you create templates for a single configuration (aka makefile), it is possible to remove everything starting from '!IF' until and including '!ENDIF' and leave only the contents of the relevant section intact. - Do not edit the lines starting with '!MESSAGE' as the changes may - and probably will - corrupt your resulting DSP files. The only thing I was able to change without corrupting the DSP is to remove the irrevant configurations from the "Possible choices for configuration are:" list.

If you have only a single configuration in your set, you may want to get rid of the intermediate dir that MsDev creates. You can do that by setting:

  1. PROP BASE Output_Dir ""
  2. PROP BASE Intermediate_Dir ""
  3. PROP Intermediate_Dir ""
  4. PROP Output_Dir "LIBRARY_OUTPUT_PATH"

or

  1. PROP Output_Dir "EXECUTABLE_OUTPUT_PATH"

Additionally you should then also edit the '# ADD LINK32' line in the DLLHeader.dsptemplate file. Change for example '/out:"LIBRARY_OUTPUT_PATHDebug/OUTPUT_LIBNAMEDEBUG_POSTFIX.dll"' into '/out:"LIBRARY_OUTPUT_PATHOUTPUT_LIBNAMEDEBUG_POSTFIX.dll"' (Note that the configuration name and also the slash are removed).

It is even possible to rename the pre-defined configurations of CMake in this way. Let's say you prefer 'PreProduction' over 'RelWithDebInfo'. You can change the name in the *.dsptemplate files, but you should also change it in the CMakeVisualStudio6Configurations.cmake file. Be careful, however. Only entries relevant to the configuration name should be changed. Do not change the /debug options and the entries that contain the build type in capital characters. Internally in CMake the build type will still remain 'RelWithDebInfo', so also the CMAKE_BUILD_TYPE should be set to the old value. You can only change the way it is named in MSDev.

Note: Apparently MsDev as command-line build tool only performs a partial check on the build type. It will match all configuration types that CONTAIN the build type in their name. (e.g. if you have renamed RelWithDebInfo to DebugRelease, Debug will build Debug and DebugRelease, Release will build Release and DebugRelease. This may be exactly what you want, but be warned.)

Can CMake set the Debugging/Working Directory property in Visual Studio projects?

Not directly. The value of this property is not stored in the project files. It is stored in extra files created by the IDE when a solution is loaded (VS .NET 2003 uses a hidden .suo file next to the .sln solution file). The format of these files is not known to CMake and cannot be generated. In some versions of VS the files are binary and not human readable.

However, for Visual Studio versions at least 2005 and newer, Ryan Pavlik maintains CMake modules that can create these files: main script, also requires this directory.

Why does CMakeSetup with the message "LINK : fatal error LNK1104: cannot open file 'user32.lib'" while configuring a project?

The path to the SDK libs (user32.lib) must be added by the IDE when the project generator "Visual Studio 8 2005" is used, because cmake uses VCExpress.exe and on the fly generated project files to check for compiling (VCExpress.exe reads some config files for the compiler/linker options)

So add the sdk lib path (...\Microsoft Platform SDK\Lib) at Tools->Options->Projects and Solutions->VC++ Directories->Library files

See also:

How can I avoid the error "Arg list too long" when running make?

This error is sometimes encountered when building a static library with many object files using Unix make command. It typically looks something like this:

gmake[2]: execvp: /bin/sh: Arg list too long

When make tries to run the archiver program to build the static library the shell it uses complains that the argument list is too long. In some shells this can be fixed by setting an environment variable such as ARG_MAX to extend the length of the command line it will allow.

The error can also happen when linking shared libraries, and can be solved by upping the sysconf parameter MAX_ARG.

On AIX this can be done with the command:

chdev -l sys0 -a ncargs='30'

How can I find out platforms definitions, search paths, etc. from gcc ?

The following is really the best if not only way to get information about predefined macros with a GNU compiler:

$ touch empty.c
$ gcc -v -dD -E empty.c 

This will give you all you might want to know about the preprocessor, the builtin include search dirs and all predefined definitions, so you can check whether it's __LINUX or _LINUX_ or _APPLE_ or __APPLE etc. The empty file and all these parameters are really required. You probably want to pipe the output (both stdout and stderr) to a file. If you want the information for C++, use a C++ file suffix for the empty file.

This is how you can get the builtin library search paths:

$ gcc --print-search-dirs

How can I get a windows registry key ?

The only thing to know is that you can't use just the "SET" command in place of "GET" command. CMake read the value from the registry only when you "get" it from the cache. For instance :

GET_FILENAME_COMPONENT(SDK_ROOT_PATH  "[HKEY_LOCAL_MACHINE\\SOFTWARE\\PACKAGE;Install_Dir]" ABSOLUTE CACHE)

If a key name (ex: Install_Dir in this case) was not specified , the Default key value will be get. Now you could use the SDK_ROOT_PATH to add include and lib path to your project :

INCLUDE_DIRECTORIES(
${SDK_ROOT_PATH}/include
)

LINK_DIRECTORIES(
${SDK_ROOT_PATH}/lib
)

You can also read a registry key in the PATHS section of a FIND_LIBRARY, FIND_PATH, FIND_PROGRAM, or FIND_FILE command

FIND_FILE(BOOT_DOT_INI boot.ini PATHS [HKEY_CURRENT_USER\\Environment;HOMEDRIVE])

For other examples have a look in the CMake Modules folder :

- FindJava.cmake
- FindPythonLibs.cmake
- ..

How can I build my MSVC application with a static runtime?

Here are three options you could employ to compile your MSVC application with /MT instead of /MD.

Manual Replace

You can rely on the user to manually modify CMAKE_C_FLAGS_DEBUG, CMAKE_C_FLAGS_RELEASE, CMAKE_CXX_FLAGS_DEBUG, CMAKE_CXX_FLAGS_RELEASE, etc. within the cache editor. After an initial configure of your software they would have to replace /MD entries with /MT.

Make Override Files

If you intend to build the entire source tree using /MT and you don't need this ever to be configurable via the CMake GUI, the best approach is to create an override file which initializes the starting cache values for the compile flags.

First create a c_flag_overrides.cmake & cxx_flag_overrides.cmake file which contain something like this... (or whatever flags you wish to use per compiler).

c_flag_overrides.cmake
    if(MSVC)
        set(CMAKE_C_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
        set(CMAKE_C_FLAGS_MINSIZEREL_INIT     "/MT /O1 /Ob1 /D NDEBUG")
        set(CMAKE_C_FLAGS_RELEASE_INIT        "/MT /O2 /Ob2 /D NDEBUG")
        set(CMAKE_C_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
    endif()
cxx_flag_overrides.cmake
    if(MSVC)
        set(CMAKE_CXX_FLAGS_DEBUG_INIT "/D_DEBUG /MTd /Zi /Ob0 /Od /RTC1")
        set(CMAKE_CXX_FLAGS_MINSIZEREL_INIT     "/MT /O1 /Ob1 /D NDEBUG")
        set(CMAKE_CXX_FLAGS_RELEASE_INIT        "/MT /O2 /Ob2 /D NDEBUG")
        set(CMAKE_CXX_FLAGS_RELWITHDEBINFO_INIT "/MT /Zi /O2 /Ob1 /D NDEBUG")
    endif()

NOTE: These files are only evaluated on the first run of CMake so they can't be dependent on a CMake option() meant to be toggled from the GUI, for example. They could be dependent on a command line -D option or an environment variable if desired.

Then enable them by setting the following variables prior to the project() command.

set(CMAKE_USER_MAKE_RULES_OVERRIDE
   ${CMAKE_CURRENT_SOURCE_DIR}/c_flag_overrides.cmake)
set(CMAKE_USER_MAKE_RULES_OVERRIDE_CXX
   ${CMAKE_CURRENT_SOURCE_DIR}/cxx_flag_overrides.cmake)
project(Bar)

Dynamic Replace

Alternatively, if you need dynamic control of /MT via some configure option you could use the following technique. Note: CMAKE_CXX_FLAGS_<FOO> is a directory level option, however. Also, this option has the downside of leaving /MD visible in the cache editor although it has no effect.

foreach(flag_var
        CMAKE_CXX_FLAGS CMAKE_CXX_FLAGS_DEBUG CMAKE_CXX_FLAGS_RELEASE
        CMAKE_CXX_FLAGS_MINSIZEREL CMAKE_CXX_FLAGS_RELWITHDEBINFO)
   if(${flag_var} MATCHES "/MD")
      string(REGEX REPLACE "/MD" "/MT" ${flag_var} "${${flag_var}}")
   endif(${flag_var} MATCHES "/MD")
endforeach(flag_var)

Other Questions

Why does CMake generate recursive Makefiles?

This question is often asked with reference to this paper:

The summary of our response may be worded "recursive make considered necessary". CMake must generate makefiles that invoke other makefiles in order to implement automatic implicit dependency scanning in combination with generated source/header files. Since CMake works with primitive UNIX make tools we may not use GNU make extensions to load new make rules into an already-running make process.

CMake does not actually generate truly recursive makefiles that follow the directory structure. It generates a fixed 3-level makefile structure in which each level has a defined purpose:

  1. Makefile: Command-line interface entry points. Maps "make" invocations into calls to the level 2 makefile:
    • make -f CMakeFiles/Makefile2 ...
  2. CMakeFiles/Makefile2: Inter-target dependencies. Evaluates targets in dependency order invoking for each target the depends and build steps in level 3:
    • make -f CMakeFiles/$(target).dir/build.make .../depend
    • make -f CMakeFiles/$(target).dir/build.make .../build
  3. CMakeFiles/<target>.dir/build.make: File-level dependencies and rules:
    • depend: Evaluates custom commands (to produce generate source files) and then scans sources for implicit dependencies.
    • build: Loads dependency scanning results from previous step. Compiles and links.



CMake: [Welcome | Site Map]