0

I have a weird problem with gcc trying to include a file twice in one compilation unit, even though there's #pragma once in that file.

The files needed to reproduce the issue are:

CMakeLists.txt

cmake_minimum_required( VERSION 3.16 )
project( example )
add_library( example SHARED src/example/class_a.cpp )
target_include_directories( example PRIVATE src )
target_precompile_headers( example PRIVATE src/example/pch.h )

src/example/class_a.cpp

#include "class_a.h"

src/example/class_a.h

#pragma once
class class_a { };

src/example/pch.h

#pragma once
#include <example/class_a.h>

Trying to compile the project leads to:

[ 33%] Building CXX object CMakeFiles/example.dir/cmake_pch.hxx.gch
[ 66%] Building CXX object CMakeFiles/example.dir/src/example/class_a.cpp.o
In file included from /src/example/class_a.cpp:1:
/src/example/class_a.h:6:7: error: redefinition of ‘class class_a’
    6 | class class_a
      |       ^~~~~~~
In file included from /src/example/pch.h:2,
                 from CMakeFiles/example.dir/cmake_pch.hxx:5,
                 from <command-line>:
/src/example/class_a.h:6:7: note: previous definition of ‘class class_a’
    6 | class class_a
      |       ^~~~~~~

If I switch the #pragma once guards to old-fashioned #ifndef XX, it compiles fine.

Also it compiles without errors if I change to "class_a.h" in pch.h file.

Am I doing something really wrong here? It really feels like a gcc bug not being able to figure out that #pragma once means "only once".

squareskittles
  • 11,997
  • 7
  • 31
  • 48
  • 1
    A bit confused how class_a.cpp finds `#include "class_a.h"` considering the only include directory you put in the CMake file is `src`, not `src/example`. Is there something not shown? What is the output when you run with `make VERBOSE=1`? – squareskittles Jun 18 '20 at 20:21
  • According to [pragma once has unfixable bugs](https://stackoverflow.com/a/34884735/4641116) by Zwol, the *author* of pragma once in GCC, "it should never be used". – Eljay Jun 18 '20 at 20:29
  • @squareskittles - class_a.cpp and class_a.h are in the same directory, unless I am missing something very basic, #include with quotes searches the file in current directory first? – user1976633 Jun 19 '20 at 06:25
  • @Eljay - I knew there are potential issues using `#pragma once`, but I thought they are related to situations where headers are being included through symbolic/hard links. In this situation the compiler is actually showing both include chains and I can clearly see `/src/example/class_a.h` being included in both of those - exactly the same name. Judging by the answer you linked, however, I am starting to think I should just accept it and put include guards everywhere. Maybe in addition to the pragmas if they really do speed up compilation as they claim. – user1976633 Jun 19 '20 at 06:43
  • I have a very large project, which these days takes about 10 minutes to full compile from a fresh clean. (Used to take 4 hours to compile, so modern machines, powerful CPU, fast RAM, and SSD have helped tremendously.) Turning **off** precompiled headers, it takes about 9 minutes to compile. Be that as it may be, I have not done any timing between guards vs pragma once. The code base uses both. The problems I've run into are different subprojects that have a different header with the same name as other headers from other subprojects, like `utility.h`. – Eljay Jun 19 '20 at 12:17

0 Answers0