Adding precompiled header support doesn't have to be a massive amount of work.

Fundamentals:

   1. Include the header in every source module,
2. Compile the header once for every target (so that compiler flags match),

There are three possible build environments:

   1. Full precompiled header support
   2. Precompiled header support for a non-PCH aware source tree,
   3. No precompiled header support,

Lets deal with #1 first; there will be a precompiled header file that needs compiling ahead of the build target. MSVC and ICC will detect incompatible PCHs and warn the user, GCC 3.4+ will do that if you specify -Winvalid-pch.

Other than that, it's a simple matter of adding defining the mechanisms per-compiler for building the PCH and telling the compiler to use it.

For MSVC/ICC "/Yu'${${PROJECT}_PCH_NAME}'".

For GCC it's a little fiddlier, because it has to be either in the same folder as the header file or before it in the search path. Adding -I ${CMAKE_BINARY_DIR} is sub-optimal because now every #include searches an extra directory.

Scenario 2 can be dealt with through the use of MSVC/ICCs /FI (force include) and gcc's -include option.

For scenario #3 there are two options. a/ For every source file, create a sourcename.pch.${SOURCE_SUFFIX} file, which contains

#include <${${PROJECT}_PCH_NAME}>
#include "${${PROJECT}$_SOURCE_DIR}/${SOURCE_FILE}"

CMake could do this fairly simply by using something like CONFIGURE_FILE.

The other would be to define a macro that the user could put in every source file that #includes the PCH, and not actually pre-compile the header file.

(If the compiler supports forced inclusion, you could use that, but I'm not aware of any compiler that supports forced includes without also supporting PCH).

Implementing a "one size fits all" PCH solution is obviously not trivial work, and I understand the "roll your own" stance being taken. But CMake could move us a long way closer to making that practical /and/ solve some other problems in a single, fairly easy to implement step that also tackles issues with wrapper systems like tolua/swig/ecpg (postgres' embedded sql in c):

   add_generated_source(
        <filepath>
        TARGET <ALL | list of targets>
        SOURCE <filepath>
        [COMPILE_FLAGS [APPEND] <additional compile flags>]
        [EXCLUDE_FLAGS] <list of compile flags to exclude>
        [CUSTOM_COMMAND <filepath> <command line arguments>]
        [DEPENDS ...]
        [WORKING_DIRECTORY <filepath>]
        [PRE_BUILD | PRE_LINK]
   )

Variables defined inside:
   ${SOURCE} The source file name (to reduce the need for duplication)
   ${SOURCE_NO_SUFFIX} The source file name minus the final suffix
   ${SOURCE_SUFFIX} The suffix of the source file
${OUTPUT} The name of the output file (allowing filepath to be "something/${SOURCE_NO_SUFFIX}.${TARGET}.${SOURCE_SUFFIX}")
   ${OUTPUT_NO_SUFFIX}
   ${OUTPUT_SUFFIX}
   ${TARGET} The name of the target I'm being applied to

This doesn't eliminate the "roll your own" PCH solution entirely, but it gives a much clearer way of describing how to do it for the majority of cases (people trying to cross-support the "Big 4" of MSVC/ICC/XCode/GNU).

Example usage with the "precompiled header" part marked bold:

   # Call user-defined macro to find tolua++, figure out which database to use, 
etc.
   find_packages()

   # Add pre-compiled header support
   IF ( MSVC )

   *    add_generated_source(
                ${Project_SOURCE_DIR}/includes/stdafx.h
                TARGET ALL
                SOURCE ${Project_SOURCE_DIR}/includes/stdafx.h
                COMPILE_FLAGS "/Yc${SOURCE}"
                EXCLUDE_FLAGS "/Yu${SOURCE}"
                PRE_BUILD
        )
   *
   ELSE IF ( COMPILER_IS_GNU )

   *     add_generated_source(
                ${Project_SOURCE_DIR}/includes/stadafx.gch
                TARGET ALL
                SOURCE ${Project_SOURCE_DIR}/includes/stdafx.h
                COMPILE_FLAGS "-o ${OUTPUT}"
                EXCLUDE_FLAGS "-include ${SOURCE}"
                PRE_BUILD
        )*

   ELSE ( COMPILER_IS_GNU )

        MESSAGE(FATAL_ERROR "Only works for MSVC/GNU")

   ENDIF ( MSVC OR COMPILER_IS_GNU )

   # Build a per-target lua wrapper.
   # i.e. build "src/luaWrapper.XXX.cc" from "etc/luaWrapper.XXX.pkg".
   # Always gets generated and then compiled just before the link step.
   add_generated_source(
        ${Project_SOURCE_DIR}/src/luaWrapper.${TARGET}.cc
        TARGET ALL
        SOURCE ${Project_SOURCE_DIR}/etc/${SOURCE_NO_SUFFIX}.${TARGET}.pkg
        CUSTOM_COMMAND ${TOULAPP_EXECUTABLE} -n ${TARGET} -o ${OUTPUT} ${SOURCE}
        *PRE_LINK
   *)


   # Library automatically gets src/luaWrapper.common.cc added to its 
compilation,
   # Also automatically builds and then includes the precompiled header with 
PROJ_LIBRARY defined.
   add_library(common
        ${Project_SOURCE_DIR}/src/common.cpp
        ${Project_SOURCE_DIR}/src/lua.cpp
   )
   set_property(TARGET common PROPERTY COMPILE_DEFINITIONS PROJ_LIBRARY)


   # Client automatically gets src/luaWrapper.client.cc added and the 
precompiled header
   # built with PROJ_CLIENT defined instead of PROJ_LIBRARY
   add_target(client
        ${Project_SOURCE_DIR}/src/clientMain.cpp
        ${Project_SOURCE_DIR}/src/clientEngine.cpp
        ${Project_SOURCE_DIR}/src/common-depends.cpp
   )
   set_property(TARGET client PROPERTY COMPILE_DEFINITIONS PROJ_CLIENT)
   target_link_libraries(common)


   # Server automatically gets src/luaWrapper.server.cc added and the 
precompiled header
   # built with PROJ_SERVER defined
   add_target(server
        ${Project_SOURCE_DIR}/src/serverMain.cpp
        ${Project_SOURCE_DIR}/src/serverEngine.cpp
        ${Project_SOURCE_DIR}/src/common-depends.cpp
        ${Project_SOURCE_DIR}/src/serverDatabase.cpp
   )
   set_property(TARGET server PROPERTY COMPILE_DEFINITIONS PROJ_SERVER 
PROJ_DATABASE=${PROJ_DATABASE})
   target_link_libraries(common ${DATABASE_LIBRARIES})

- Oliver
_______________________________________________
Powered by www.kitware.com

Visit other Kitware open-source projects at 
http://www.kitware.com/opensource/opensource.html

Please keep messages on-topic and check the CMake FAQ at: 
http://www.cmake.org/Wiki/CMake_FAQ

Follow this link to subscribe/unsubscribe:
http://www.cmake.org/mailman/listinfo/cmake

Reply via email to