[CMake] -fPIC and precompiled header

Maik Beckmann maikbeckmann at gmx.de
Sat Dec 23 05:26:08 EST 2006


Am Mittwoch, den 20.12.2006, 17:53 +0100 schrieb frederic heem:
> Hi,
> Is there a nice way to find out if a target is using -fPIC ?
> Indeed, this information is needed for generating compiled header. 
> At the moment, a kludge is to use the following code:
> 
>     #If the target is a shared library, add -fPIC to compile
>     GET_TARGET_PROPERTY(_targetType ${_targetName} TYPE)
>     IF(${_targetType} STREQUAL SHARED_LIBRARY)
>       SET(_compile_FLAGS "${_compile_FLAGS} -fPIC")
>     ENDIF(${_targetType} STREQUAL SHARED_LIBRARY)
> 
> This works but is not a proper solution, one shall not know in which 
> case -fPIC is used or not.
> Thanks,
> Frederic Heem

I ran into this problem and your solutions works like a charm. 

I also worked on msvc support(see attached file), but it only work if
CMAKE_BUILD_TYPE equals "Release", since /Fd wants to add debugging
informations and fails due to inconsitent pdb files. If someone know's
more about this issue, please give me a hint.

merry Christmas, Maik
-------------- next part --------------
# - Try to find precompiled headers support for GCC 3.4 and 4.x
# Once done this will define:
#
# Variable:
#   PCHSupport_FOUND
#
# Macro:
#   ADD_PRECOMPILED_HEADER

IF(CMAKE_COMPILER_IS_GNUCXX)

    EXEC_PROGRAM(
    	${CMAKE_CXX_COMPILER} 
        ARGS 			--version 
        OUTPUT_VARIABLE _compiler_output)
    STRING(REGEX REPLACE ".* ([0-9]\\.[0-9]\\.[0-9]) .*" "\\1" 
           gcc_compiler_version ${_compiler_output})
    #MESSAGE("GCC Version: ${gcc_compiler_version}")
    IF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]")
        SET(PCHSupport_FOUND TRUE)
    ELSE(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]")
        IF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]")
            SET(PCHSupport_FOUND TRUE)
        ENDIF(gcc_compiler_version MATCHES "3\\.4\\.[0-9]")
    ENDIF(gcc_compiler_version MATCHES "4\\.[0-9]\\.[0-9]")
    
	SET(_PCH_include_prefix "-I")
	
ELSE(CMAKE_COMPILER_IS_GNUCXX)
	
	SET(PCHSupport_FOUND TRUE) # for experimental msvc support
	SET(_PCH_include_prefix "/I")
	
ENDIF(CMAKE_COMPILER_IS_GNUCXX)



MACRO(_PCH_GET_COMPILE_FLAGS _out_compile_flags)


	STRING(TOUPPER "CMAKE_CXX_FLAGS_${CMAKE_BUILD_TYPE}" _flags_var_name)
    SET(_compile_FLAGS ${${_flags_var_name}} )


	IF(CMAKE_COMPILER_IS_GNUCXX)
	
    	GET_TARGET_PROPERTY(_targetType ${_PCH_current_target} TYPE)
    	IF(${_targetType} STREQUAL SHARED_LIBRARY)
      		LIST(APPEND _compile_FLAGS "${_compile_FLAGS} -fPIC")
    	ENDIF(${_targetType} STREQUAL SHARED_LIBRARY)
	
	ELSE(CMAKE_COMPILER_IS_GNUCXX)
		## TODO ... ? or does it work out of the box 
	ENDIF(CMAKE_COMPILER_IS_GNUCXX)
    	
	FOREACH(item ${_directory_flags})
		LIST(APPEND _compile_FLAGS "${_PCH_include_prefix}${item}")
    ENDFOREACH(item)

	GET_DIRECTORY_PROPERTY(_directory_flags DEFINITIONS)
    LIST(APPEND _compile_FLAGS ${_directory_flags})
	LIST(APPEND _compile_FLAGS ${CMAKE_CXX_FLAGS} )

    SEPARATE_ARGUMENTS(_compile_FLAGS)

ENDMACRO(_PCH_GET_COMPILE_FLAGS)



MACRO(_PCH_TEST_PATH _path )

	GET_DIRECTORY_PROPERTY(_directory_flags INCLUDE_DIRECTORIES)

	SET(_CMAKE_CURRENT_BINARY_DIR_included_before_path FALSE)
	FOREACH(item ${_directory_flags})
		IF(${item}  STREQUAL ${_path} AND NOT _CMAKE_CURRENT_BINARY_DIR_included_before_path )
			MESSAGE(FATAL_ERROR 
				"This is the ADD_PRECOMPILED_HEADER macro. "
				"CMAKE_CURREN_BINARY_DIR has to mentioned at INCLUDE_DIRECTORIES's argument list before :${_path}:, where ${_name} is located"
			)	
		ENDIF(${item}  STREQUAL ${_path} AND NOT _CMAKE_CURRENT_BINARY_DIR_included_before_path )
	
		IF(${item}  STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
			SET(_CMAKE_CURRENT_BINARY_DIR_included_before_path TRUE)
		ENDIF(${item}  STREQUAL ${CMAKE_CURRENT_BINARY_DIR})
    ENDFOREACH(item)
    
ENDMACRO(_PCH_TEST_PATH)



MACRO(_PCH_GET_COMPILE_COMMAND out_command _input _output)

	FILE(TO_NATIVE_PATH ${_input} _native_input)
	FILE(TO_NATIVE_PATH ${_output} _native_output)
	

	IF(CMAKE_COMPILER_IS_GNUCXX)
	
		SET(${out_command} 
			${CMAKE_CXX_COMPILER} ${_compile_FLAGS}	-x c++-header -o ${_output} ${_input} 
		)
	
	ELSE(CMAKE_COMPILER_IS_GNUCXX)
		
		SET(_dummy_str "#include <${_input}>")
		FILE(WRITE ${CMAKE_CURRENT_BINARY_DIR}/pch_dummy.cpp ${_dummy_str})
	
		SET(${out_command} 
			${CMAKE_CXX_COMPILER} ${_compile_FLAGS} /c /Fp${_native_output} /Yc${_native_input} pch_dummy.cpp
		)	
		#/out:${_output}

	ENDIF(CMAKE_COMPILER_IS_GNUCXX)
	
ENDMACRO(_PCH_GET_COMPILE_COMMAND )



MACRO(_PCH_GET_TARGET_COMPILE_FLAGS _cflags  _header_name _pch_path  )

	FILE(TO_NATIVE_PATH ${_pch_path} _native_pch_path)
	message(${_native_pch_path})

	IF(CMAKE_COMPILER_IS_GNUCXX)
	
		set(${_cflags} "-include ${_header_name} -Winvalid-pch" )
	
	ELSE(CMAKE_COMPILER_IS_GNUCXX)

		set(${_cflags} "/Fp${_native_pch_path} /Yu${_header_name}" )	

	ENDIF(CMAKE_COMPILER_IS_GNUCXX)	

ENDMACRO(_PCH_GET_TARGET_COMPILE_FLAGS )



MACRO(ADD_PRECOMPILED_HEADER _targetName _input )

	SET(_PCH_current_target ${_targetName})

	IF(NOT CMAKE_BUILD_TYPE)
		MESSAGE(FATAL_ERROR 
			"This is the ADD_PRECOMPILED_HEADER macro. " 
			"You must set CMAKE_BUILD_TYPE!"
		)
	ENDIF(NOT CMAKE_BUILD_TYPE)

    GET_FILENAME_COMPONENT(_name ${_input} NAME)
	GET_FILENAME_COMPONENT(_path ${_input} PATH)
    SET(_outdir "${CMAKE_CURRENT_BINARY_DIR}/${_name}.gch")
	SET(_output "${_outdir}/${CMAKE_BUILD_TYPE}.c++")

    ADD_CUSTOM_COMMAND(
		OUTPUT ${_outdir}
		COMMAND mkdir ${_outdir} # TODO: {CMAKE_COMMAND} -E ... !doesn't work in win32
	)
    
    _PCH_TEST_PATH(_path)
    _PCH_GET_COMPILE_FLAGS(_compile_FLAGS)

    #MESSAGE("_compiler_FLAGS: ${_compiler_FLAGS}")
	message(${_compile_FLAGS} )
    #message("COMMAND ${CMAKE_CXX_COMPILER}	${_compile_FLAGS} -x c++-header -o ${_output} ${_input}")
	
	ADD_CUSTOM_COMMAND(
		OUTPUT	${CMAKE_CURRENT_BINARY_DIR}/${_name} 
		COMMAND ${CMAKE_COMMAND} -E copy  ${_input} ${CMAKE_CURRENT_BINARY_DIR}/${_name} # ensure same directory! Required by gcc
	)

	#message("_command  ${_input} ${_output}")
	_PCH_GET_COMPILE_COMMAND(_command  ${_input} ${_output} )

	#message(${_input} )
	message("${_command}")

    ADD_CUSTOM_COMMAND(
        OUTPUT ${_output} 	
		COMMAND ${_command}
        DEPENDS ${_input} ${_outdir} ${CMAKE_CURRENT_BINARY_DIR}/${_name}	
	)
   	ADD_CUSTOM_TARGET(${_targetName}_gch 
		DEPENDS	${_output} 	
	)
    ADD_DEPENDENCIES(${_targetName} ${_targetName}_gch )
   
   _PCH_GET_TARGET_COMPILE_FLAGS(_target_cflags ${_name} ${_output})
    
    #message("${_target_cflags}")
    
    SET_TARGET_PROPERTIES(${_targetName} 
		PROPERTIES	
			COMPILE_FLAGS ${_target_cflags} 
    )
	
	
ENDMACRO(ADD_PRECOMPILED_HEADER)



More information about the CMake mailing list