<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN">
<html>
<head>
</head>
<body bgcolor="#ffffff" text="#000000">
Adding precompiled header support doesn't have to be a massive amount
of work.<br>
<br>
Fundamentals:<br>
<br>
&nbsp;&nbsp;&nbsp; 1. Include the header in every source module,<br>
&nbsp;&nbsp;&nbsp; 2. Compile the header once for every target (so that compiler flags
match),<br>
<br>
There are three possible build environments:<br>
<br>
&nbsp;&nbsp;&nbsp; 1. Full precompiled header support<br>
&nbsp;&nbsp;&nbsp; 2. Precompiled header support for a non-PCH aware source tree,<br>
&nbsp;&nbsp;&nbsp; 3. No precompiled header support,<br>
<br>
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.<br>
<br>
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.<br>
<br>
For MSVC/ICC "/Yu'${${PROJECT}_PCH_NAME}'".<br>
<br>
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.<br>
<br>
Scenario 2 can be dealt with through the use of MSVC/ICCs /FI (force
include) and gcc's -include option.<br>
<br>
For scenario #3 there are two options. a/ For every source file, create
a sourcename.pch.${SOURCE_SUFFIX} file, which contains<br>
<br>
#include &lt;${${PROJECT}_PCH_NAME}&gt;<br>
#include "${${PROJECT}$_SOURCE_DIR}/${SOURCE_FILE}"<br>
<br>
CMake could do this fairly simply by using something like
CONFIGURE_FILE.<br>
<br>
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.<br>
<br>
(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).<br>
<br>
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 <i>and</i>
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):<br>
<pre>&nbsp;&nbsp;&nbsp; add_generated_source(
        &lt;filepath&gt;
        TARGET &lt;ALL | list of targets&gt;
        SOURCE &lt;filepath&gt;
        [COMPILE_FLAGS [APPEND] &lt;additional compile flags&gt;]
        [EXCLUDE_FLAGS] &lt;list of compile flags to exclude&gt;
        [CUSTOM_COMMAND &lt;filepath&gt; &lt;command line arguments&gt;]
        [DEPENDS ...]
        [WORKING_DIRECTORY &lt;filepath&gt;]
        [PRE_BUILD | PRE_LINK]
    )
</pre>
Variables defined inside:<br>
&nbsp;&nbsp;&nbsp; ${SOURCE} The source file name (to reduce the need for duplication)<br>
&nbsp;&nbsp;&nbsp; ${SOURCE_NO_SUFFIX} The source file name minus the final suffix<br>
&nbsp;&nbsp;&nbsp; ${SOURCE_SUFFIX} The suffix of the source file<br>
&nbsp;&nbsp;&nbsp; ${OUTPUT} The name of the output file (allowing filepath to be
"something/${SOURCE_NO_SUFFIX}.${TARGET}.${SOURCE_SUFFIX}")<br>
&nbsp;&nbsp;&nbsp; ${OUTPUT_NO_SUFFIX}<br>
&nbsp;&nbsp;&nbsp; ${OUTPUT_SUFFIX}<br>
&nbsp;&nbsp;&nbsp; ${TARGET} The name of the target I'm being applied to<br>
<br>
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).<br>
<br>
Example usage with the "precompiled header" part marked bold:<br>
<blockquote>
  <pre># Call user-defined macro to find tolua++, figure out which database to use, etc.
find_packages()

# Add pre-compiled header support
IF ( MSVC )

<b>        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
        )
</b>
ELSE IF ( COMPILER_IS_GNU )

<b>        &nbsp;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
        )</b>

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}
        <b>PRE_LINK
</b>)


# 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})
  </pre>
</blockquote>
<br>
- Oliver
</body>
</html>