Skip to content

Commit

Permalink
Added precompiled header support.
Browse files Browse the repository at this point in the history
Precompiled headers are used by default on Windows because they
reduce compile time significantly.  They are not used by default
elsewhere because they significantly slow down compile time.
The PXR_ENABLE_PRECOMPILED_HEADERS option controls whether
precompiled headers are used or not.

If enabled, precompiled headers are used for shared libraries,
static libraries, and plugins.  They can be disabled by using
the DISABLE_PRECOMPILED_HEADERS option to the call to
pxr_shared_library, etc.  The default name for the header to be
precompiled is pch.h but this can be overridden per library/plugin
with the PRECOMPILED_HEADER_NAME argument to pxr_shared_library,
etc. or globally with PXR_PRECOMPILED_HEADER_NAME, with the
former having precedence over the latter.  The comments below
assume the name is pch.h.

When a precompiled header is enabled each C++ compile implicitly
includes the pch.h header before everything else.  So other than
creating the pch.h file there should be no other changes to the
code needed to use precompiled headers.  However, if there is no
pch.h to precompile then DISABLE_PRECOMPILED_HEADERS must be
added so cmake doesn't look for it.

There's a problem using 'def(str(self))' when wrapping a class
to Python using boost python.  For some reason the appropriate
overload isn't deduced (or something) and the code fails to
compile when using precompiled headers.  For now we simply
replace that code with something more explicit but equivalent.

There was also a problem in a few places where a macro was
defined (to affect later macros) but there aren't any guards
around it to prevent redefinition (as there will be when using
precompiled headers).  The guards were added.

Some other tweaks were made as well to simplify the job of a
script (not included in this checkin) to automatically generate
the pch.h files from the code.

(Internal change: 1733379)
  • Loading branch information
pixar-oss committed Apr 7, 2017
1 parent 0adfbb8 commit 791bdb6
Show file tree
Hide file tree
Showing 62 changed files with 6,456 additions and 36 deletions.
12 changes: 12 additions & 0 deletions cmake/defaults/Options.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,18 @@ option(PXR_ENABLE_PTEX_SUPPORT "Enable Ptex support" ON)
option(PXR_MAYA_TBB_BUG_WORKAROUND "Turn on linker flag (-Wl,-Bsymbolic) to work around a Maya TBB bug" OFF)
option(PXR_ENABLE_NAMESPACES "Enable C++ namespaces." OFF)

# Precompiled headers are a win on Windows, not on gcc.
set(pxr_enable_pch "OFF")
if(MSVC)
set(pxr_enable_pch "ON")
endif()
option(PXR_ENABLE_PRECOMPILED_HEADERS "Enable precompiled headers." "${pxr_enable_pch}")
set(PXR_PRECOMPILED_HEADER_NAME "pch.h"
CACHE
STRING
"Default name of precompiled header files"
)

set(PXR_INSTALL_LOCATION ""
CACHE
STRING
Expand Down
233 changes: 233 additions & 0 deletions cmake/macros/Private.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -346,3 +346,236 @@ function(_append_to_rpath orig_rpath new_rpath output)
set(${output} "${orig_rpath}:${new_rpath}" PARENT_SCOPE)
endif()
endfunction() # _add_to_rpath

function(_get_directory_property property separator output)
get_property(value DIRECTORY PROPERTY ${property})
if(NOT value STREQUAL "value-NOTFOUND")
# XXX -- Need better list joining.
if(${output})
set(${output} "${${output}}${separator}${value}" PARENT_SCOPE)
else()
set(${output} "${value}" PARENT_SCOPE)
endif()
endif()
endfunction()

function(_get_target_property target property separator output)
get_property(value TARGET ${target} PROPERTY ${property})
if(NOT value STREQUAL "value-NOTFOUND")
# XXX -- Need better list joining.
if(${output})
set(${output} "${${output}}${separator}${value}" PARENT_SCOPE)
else()
set(${output} "${value}" PARENT_SCOPE)
endif()
endif()
endfunction()

function(_get_property target property output)
set(sep ";")
if("${property}" STREQUAL "COMPILE_FLAGS")
set(sep " ")
set(accum "${accum}${sep}${CMAKE_CXX_FLAGS}")
if(CMAKE_BUILD_TYPE)
string(TOUPPER ${CMAKE_BUILD_TYPE} buildType)
set(accum "${accum}${sep}${CMAKE_CXX_FLAGS_${buildType}}")
endif()
endif()
_get_directory_property(${property} "${sep}" accum)
_get_target_property(${target} ${property} "${sep}" accum)
set(${output} "${accum}" PARENT_SCOPE)
endfunction()

function(_pxr_enable_precompiled_header TARGET_NAME)
# Ignore if disabled.
if(NOT PXR_ENABLE_PRECOMPILED_HEADERS)
return()
endif()

set(options
)
set(oneValueArgs
SOURCE_NAME
OUTPUT_NAME_PREFIX
)
set(multiValueArgs
EXCLUDE
)
cmake_parse_arguments(pch
"${options}"
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)

# Header to precompile. SOURCE_NAME falls back to
# ${PXR_PRECOMPILED_HEADER_NAME}.
if("${pch_SOURCE_NAME}" STREQUAL "")
set(pch_SOURCE_NAME "${PXR_PRECOMPILED_HEADER_NAME}")
endif()
if("${pch_SOURCE_NAME}" STREQUAL "")
# Emergency backup name is "pch.h".
set(pch_SOURCE_NAME "pch.h")
endif()
set(source_header_name ${pch_SOURCE_NAME})
get_filename_component(source_header_name_we ${source_header_name} NAME_WE)

# Name of file to precompile in the build directory. The client can
# specify a prefix for this file, allowing multiple binaries/libraries
# in a single subdirectory to use unique precompiled headers, meaning
# each can have different compile options.
set(output_header_name_we "${pch_OUTPUT_NAME_PREFIX}${source_header_name_we}")
set(output_header_name ${output_header_name_we}.h)

# Precompiled header file name. We choose the name that matches the
# convention for the compiler. That isn't necessary since we give
# this name explicitly wherever it's needed.
if(MSVC)
set(precompiled_name ${output_header_name_we}.pch)
elseif(CMAKE_COMPILER_IS_GNUCXX)
set(precompiled_name ${output_header_name_we}.h.gch)
elseif("${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang")
set(precompiled_name ${output_header_name_we}.h.pch)
else()
# Silently ignore unknown compiler.
return()
endif()

# Headers live in subdirectories.
set(rel_output_header_path "${PXR_PREFIX}/${TARGET_NAME}/${output_header_name}")
set(abs_output_header_path "${CMAKE_BINARY_DIR}/include/${rel_output_header_path}")
set(abs_precompiled_path ${CMAKE_BINARY_DIR}/include/${PXR_PREFIX}/${TARGET_NAME}/${precompiled_name})

# Additional compile flags to use precompiled header. This will be
set(compile_flags "")
if(MSVC)
# Build with precompiled header (/Yu, /Fp) and automatically
# include the header (/FI).
set(compile_flags "/Yu\"${rel_output_header_path}\" /FI\"${rel_output_header_path}\" /Fp\"${abs_precompiled_path}\"")
else()
# Automatically include the header (-include) and warn if there's
# a problem with the precompiled header.
set(compile_flags "-Winvalid-pch -include \"${rel_output_header_path}\"")
endif()

# Use FALSE if we have an external precompiled header we can use.
if(TRUE)
if(MSVC)
# Copy the header to precompile.
add_custom_command(
OUTPUT "${abs_output_header_path}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${source_header_name}" "${abs_output_header_path}"
DEPENDS "${source_header_name}"
COMMENT "Copying ${source_header_name}"
)

# Make an empty trigger file. We need a source file to do the
# precompilation. This file only needs to include the header to
# precompile but we're implicitly including that header so this
# file can be empty.
set(abs_output_source_path ${CMAKE_CURRENT_BINARY_DIR}/${output_header_name_we}.cpp)
add_custom_command(
OUTPUT "${abs_output_source_path}"
COMMAND ${CMAKE_COMMAND} -E touch ${abs_output_source_path}
)

# The trigger file gets a special compile flag (/Yc).
set_source_files_properties(${abs_output_source_path} PROPERTIES
COMPILE_FLAGS "/Yc\"${rel_output_header_path}\" /FI\"${rel_output_header_path}\" /Fp\"${abs_precompiled_path}\""
OBJECT_OUTPUTS "${abs_precompiled_path}"
OBJECT_DEPENDS "${abs_output_header_path}"
)

# Add the header file to the target.
target_sources(${TARGET_NAME} PRIVATE "${abs_output_header_path}")

# Add the trigger file to the target.
target_sources(${TARGET_NAME} PRIVATE "${abs_output_source_path}")

# Exclude the trigger.
list(APPEND pch_EXCLUDE ${abs_output_source_path})
else()
# Copy the header to precompile.
add_custom_command(
OUTPUT "${abs_output_header_path}"
COMMAND ${CMAKE_COMMAND} -E copy_if_different "${CMAKE_CURRENT_SOURCE_DIR}/${source_header_name}" "${abs_output_header_path}"
DEPENDS "${source_header_name}"
COMMENT "Copying ${source_header_name}"
)

# CMake has no simple way of invoking the compiler with additional
# arguments so we must make a custom command and pass the compiler
# arguments we collect here.
#
# $<JOIN:...> is available starting with 2.8.12. In later
# cmake versions getting the target properties may not
# report all values (in particular, some include directories
# may not be reported).
if(CMAKE_VERSION VERSION_LESS "2.8.12")
_get_property(${TARGET_NAME} INCLUDE_DIRECTORIES incs)
_get_property(${TARGET_NAME} COMPILE_DEFINITIONS defs)
_get_property(${TARGET_NAME} COMPILE_FLAGS flags)
_get_property(${TARGET_NAME} COMPILE_OPTIONS opts)
if(NOT "${incs}" STREQUAL "")
string(REPLACE ";" ";-I" incs "${incs}")
set(incs "-I${incs}")
endif()
if(NOT "${defs}" STREQUAL "")
string(REPLACE ";" ";-D" defs "${defs}")
set(defs "-D${defs}")
endif()
separate_arguments(flags UNIX_COMMAND "${flags}")

# Command to generate the precompiled header.
add_custom_command(
OUTPUT "${abs_precompiled_path}"
COMMAND ${CMAKE_CXX_COMPILER} ${flags} ${opts} ${defs} ${incs} -c -x c++-header -o "${abs_precompiled_path}" "${abs_output_header_path}"
DEPENDS "${abs_output_header_path}"
COMMENT "Precompiling ${source_header_name} in ${TARGET_NAME}"
)
else()
set(incs "$<TARGET_PROPERTY:${TARGET_NAME},INCLUDE_DIRECTORIES>")
set(defs "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_DEFINITIONS>")
set(opts "$<TARGET_PROPERTY:${TARGET_NAME},COMPILE_OPTIONS>")
set(incs "$<$<BOOL:${incs}>:-I$<JOIN:${incs}, -I>>")
set(defs "$<$<BOOL:${defs}>:-D$<JOIN:${defs}, -D>>")
_get_property(${TARGET_NAME} COMPILE_FLAGS flags)

# Ideally we'd just put have generator expressions in the
# COMMAND in add_custom_command(). However that will
# write the result of the JOINs as single strings (escaping
# spaces) and we want them as individual options.
#
# So we use file(GENERATE) which doesn't suffer from that
# problem and execute the generated cmake script as the
# COMMAND.
file(GENERATE
OUTPUT "$<TARGET_FILE:${TARGET_NAME}>.pchgen"
CONTENT "execute_process(COMMAND ${CMAKE_CXX_COMPILER} ${flags} ${opt} ${defs} ${incs} -c -x c++-header -o \"${abs_precompiled_path}\" \"${abs_output_header_path}\")"
)

# Command to generate the precompiled header.
add_custom_command(
OUTPUT "${abs_precompiled_path}"
COMMAND ${CMAKE_COMMAND} -P "$<TARGET_FILE:${TARGET_NAME}>.pchgen"
DEPENDS "${abs_output_header_path}"
COMMENT "Precompiling ${source_header_name} in ${TARGET_NAME}"
)
endif()
endif()
endif()

# Update every C++ source in the target to implicitly include and
# depend on the precompiled header.
get_property(target_sources TARGET ${TARGET_NAME} PROPERTY SOURCES)
foreach(source ${target_sources})
# All target C++ sources not in EXCLUDE list.
if(source MATCHES \\.cpp$)
if (NOT ";${pch_EXCLUDE};" MATCHES ";${source};")
set_source_files_properties(${source} PROPERTIES
COMPILE_FLAGS "${compile_flags}"
OBJECT_DEPENDS "${abs_precompiled_path}")
endif()
endif()
endforeach()
endfunction()
55 changes: 53 additions & 2 deletions cmake/macros/Public.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -158,8 +158,12 @@ function(pxr_cpp_bin BIN_NAME)
endfunction()

function(pxr_shared_library LIBRARY_NAME)
set(options PYTHON_LIBRARY)
set(options
DISABLE_PRECOMPILED_HEADERS
PYTHON_LIBRARY
)
set(oneValueArgs
PRECOMPILED_HEADER_NAME
PYTHON_WRAPPED_LIB_PREFIX
)
set(multiValueArgs
Expand Down Expand Up @@ -419,6 +423,7 @@ function(pxr_shared_library LIBRARY_NAME)
PYTHON_WRAPPED_LIB_PREFIX ${LIB_INSTALL_PREFIX}
CPPFILES ${sl_PYMODULE_CPPFILES}
LIBRARIES ${LIBRARY_NAME}
INCLUDE_DIRS ${sl_INCLUDE_DIRS}
)
endif()

Expand All @@ -441,9 +446,29 @@ function(pxr_shared_library LIBRARY_NAME)
_install_pyside_ui_files(${sl_PYSIDE_UI_FILES})
endif()

if(NOT "${PXR_PREFIX}" STREQUAL "")
if(NOT sl_DISABLE_PRECOMPILED_HEADERS)
if(NOT sl_PYTHON_LIBRARY)
_pxr_enable_precompiled_header(${LIBRARY_NAME}
SOURCE_NAME "${sl_PRECOMPILED_HEADER_NAME}"
)
else()
_pxr_enable_precompiled_header(${LIBRARY_NAME}
OUTPUT_NAME_PREFIX "py"
SOURCE_NAME "${sl_PRECOMPILED_HEADER_NAME}"
)
endif()
endif()
endif()
endfunction() # pxr_shared_library

function(pxr_static_library LIBRARY_NAME)
set(options
DISABLE_PRECOMPILED_HEADERS
)
set(oneValueArgs
PRECOMPILED_HEADER_NAME
)
set(multiValueArgs
PUBLIC_CLASSES
PUBLIC_HEADERS
Expand All @@ -456,7 +481,7 @@ function(pxr_static_library LIBRARY_NAME)

cmake_parse_arguments(sl
"${options}"
""
"${oneValueArgs}"
"${multiValueArgs}"
${ARGN}
)
Expand Down Expand Up @@ -572,13 +597,23 @@ function(pxr_static_library LIBRARY_NAME)
${sl_INCLUDE_DIRS}
)
endif()

if(NOT "${PXR_PREFIX}" STREQUAL "")
if(NOT sl_DISABLE_PRECOMPILED_HEADERS)
_pxr_enable_precompiled_header(${LIBRARY_NAME}
SOURCE_NAME "${sl_PRECOMPILED_HEADER_NAME}"
)
endif()
endif()
endfunction() # pxr_static_library

function(pxr_plugin PLUGIN_NAME)
set(options
DISABLE_PRECOMPILED_HEADERS
KATANA_PLUGIN
)
set(oneValueArgs
PRECOMPILED_HEADER_NAME
PREFIX
)
set(multiValueArgs
Expand Down Expand Up @@ -800,8 +835,24 @@ function(pxr_plugin PLUGIN_NAME)
PYTHON_WRAPPED_LIB_PREFIX ${PLUGIN_INSTALL_PREFIX}
CPPFILES ${sl_PYMODULE_CPPFILES}
LIBRARIES ${PLUGIN_NAME}
INCLUDE_DIRS ${sl_INCLUDE_DIRS}
)
endif()

if(NOT "${PXR_PREFIX}" STREQUAL "")
if(NOT sl_DISABLE_PRECOMPILED_HEADERS)
if(NOT sl_PYTHON_LIBRARY)
_pxr_enable_precompiled_header(${LIBRARY_NAME}
SOURCE_NAME "${sl_PRECOMPILED_HEADER_NAME}"
)
else()
_pxr_enable_precompiled_header(${LIBRARY_NAME}
OUTPUT_NAME_PREFIX "py"
SOURCE_NAME "${sl_PRECOMPILED_HEADER_NAME}"
)
endif()
endif()
endif()
endfunction() # pxr_plugin

function(pxr_setup_python)
Expand Down
Loading

0 comments on commit 791bdb6

Please sign in to comment.