0

I'm trying to precompile my headers using gcc and cmake.

I know some scripts like cotire or customPCH do it, but I would like to write my own script.

The project is pretty simple : there is a shared library with some files, and a main calling functions defined in those files. I have manages to build the library (with precompiled header), but I have a strange compilation error when building the main ("precompiled.hpp", no such file or directory), even if the preompiled header is in the include search path (the library uses the same include paths and does not complain)

[100%] Building CXX object CMakeFiles/prog.dir/src/bin/main.cpp.o
/usr/bin/c++ -DUSE_PRECOMPILED -Isrc -Ibuild -Winvalid-pch -fPIC -o CMakeFiles/prog.dir/src/bin/main.cpp.o -c src/bin/main.cpp
src/lib/dir2/file2.hpp:7:42: fatal error: build/precompiled_header.hpp: No such file or directory
     #include "precompiled_header.hpp"

I have set up a working toy example available here : git clone -b toy https://bitbucket.org/mrdut/precompiled_header.git

Does anyone have any advice ?

Thanks in advance,

Here is the content of my project:

run.sh
CMakeLists.txt
src/
   lib/
      dir1/file1.cpp, file1.hpp
      dir2/file2.cpp, file2.hpp
   bin/main.cpp

run.sh :

mkdir build
cd build/
cmake .. && make VERBOSE=1 && ./bin/prog
cd ..

CMakeslist.txt :

cmake_minimum_required(VERSION 2.8.11)

project('PRECOMPILED' CXX)

set(CMAKE_RUNTIME_OUTPUT_DIRECTORY bin)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY lib)

add_compile_options(-Winvalid-pch)

set(use_precompiled_header 1) # <= everything is fine if not using precompiled header
set(executable_name prog)
set(library_name erty)
set(precompiled_header_name precompiled_header )

###########
# library #
###########
add_library(${library_name} SHARED src/lib/dir1/file1.cpp src/lib/dir2/file2.cpp)
target_include_directories(${library_name} PUBLIC src )

##############
# executable #
##############
add_executable(${executable_name} src/bin/main.cpp)
target_include_directories(${executable_name} PUBLIC src )
target_link_libraries(${executable_name} ${library_name})
target_compile_options(${executable_name} PRIVATE "-fPIC") # because we are building SHARED library

######################
# precompiled header #
######################
if( ${use_precompiled_header} )

    set(precompiled_header_dir ${CMAKE_CURRENT_BINARY_DIR} )
    set(precompiled_header_src ${CMAKE_CURRENT_SOURCE_DIR}/src/header.hpp )
    set(precompiled_header_dst precompiled_header.hpp.gch )

    add_custom_target( ${precompiled_header_name} ALL DEPENDS ${precompiled_header_dst} )
    add_custom_command( OUTPUT ${precompiled_header_dst}
                            COMMAND ${CMAKE_CXX_COMPILER} -fPIC -DUSE_PRECOMPILED ${precompiled_header_src} -o ${precompiled_header_dst}
                            MAIN_DEPENDENCY ${precompiled_header_src}
                            WORKING_DIRECTORY ${precompiled_header_dir}
                            VERBATIM )

    add_dependencies( ${library_name} ${precompiled_header_name} )

    target_compile_definitions(${library_name} PUBLIC -DUSE_PRECOMPILED )
    target_compile_definitions(${executable_name} PUBLIC -DUSE_PRECOMPILED )

    target_include_directories(${library_name} PUBLIC ${precompiled_header_dir})
    target_include_directories(${executable_name} PUBLIC ${precompiled_header_dir})

endif()

src/header.hpp :

#ifndef HEADER_HPP
#define HEADER_HPP
    #include <iostream>
#endif

src/bin/main.cpp :

#include "lib/dir1/file1.hpp"
#include "lib/dir2/file2.hpp"
int main(int argc, char** argv)
{
    std::cout << "\n -= " << argv[0] << " =-\n";
    libfunc1();
    libfunc2();
    return 0;
}

src/lib.dir1/file1.cpp :

#include "lib/dir1/file1.hpp"
void libfunc1() { std::cout << "function 1" << std::endl; }

src/lib.dir1/file1.hpp :

#ifndef LIBRARY_FILE_1_HPP
#define LIBRARY_FILE_1_HPP
    #ifndef USE_PRECOMPILED
        #include "header.hpp"
    #else
        #include "precompiled_header.hpp"
    #endif
    void libfunc1();
#endif

src/lib.dir2/file2.cpp :

#include "lib/dir2/file2.hpp"
void libfunc2() { std::cout << "function 2" << std::endl; }

src/lib.dir1/file2.hpp:

#ifndef LIBRARY_FILE_2_HPP
#define LIBRARY_FILE_2_HPP
    #ifndef USE_PRECOMPILED
        #include "header.hpp"
    #else
        #include "precompiled_header.hpp"
    #endif
    void libfunc2();
#endif
flod
  • 235
  • 4
  • 12
  • `I have manages to build the library (with precompiled header), but I have a strange compilation error when building the main` - Please, provide your code in form of [MCVE](http://stackoverflow.com/help/mcve) and error message, which is caused by the code. – Tsyvarev Nov 09 '15 at 17:01
  • Thanks for your advice, I have updated my post – flod Nov 09 '15 at 17:46

2 Answers2

0

Because file1.hpp and file2.hpp include your precompiled_header.hpp you need precompile them also for make things work.

From the gcc precompiled headers documentation:

A precompiled header can't be used once the first C token is seen. You can have preprocessor directives before a precompiled header; you cannot include a precompiled header from inside another header.

Tsyvarev
  • 60,011
  • 17
  • 110
  • 153
0

It seems to work if I include first the precompiled header before the other header in the main.cpp

#ifdef USE_PRECOMPILED
    #include "precompiled_header.hpp"
    #undef USE_PRECOMPILED
#endif
flod
  • 235
  • 4
  • 12
  • Such a way you use both normal header `header.hpp` from `main.cpp` and precompiled one `precompiled_header.hpp` from `file.hpp`(also included from `main.cpp`). Such usage just eliminates needs of precompiled header, which is probably not what you want. – Tsyvarev Nov 09 '15 at 21:36