MartiSanchez
MartiSanchez

Reputation: 61

unterminated unconditional directive error when preprocessing C code

I am having an error in the preprocessing step when compiling a C program.

The odd thing is that I can run the preprocessing with no errors or warnings using:

gcc -I/usr/local/libpng-1.6.24/include -Wall -std=c99 lines.c -E -o lines

but using the form below give me errors:

cpp -I/usr/local/libpng-1.6.24/include -std=c99 lines.c -o lines

I am assuming that cpp is run as part of gcc what makes it more wierd.

For information see below the error I am getting -only one of them, I have many of them of the same sort:

In file included from lines.c:1:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/stdio.h:65:
In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/Availability.h:172:
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/usr/include/AvailabilityInternal.h:15284:10: error:
    unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11

Needless to notice that the file with the error is a Apple standard file. I must say also that it seems all right to me having all terminating #endif matching their #if directives

Any idea what could be happening here? Or way forward to track down the error?

PS By the way I am running this in OSX with developer tools provided standard by Apple.

--

Adding additional information as a response to some comments:

The source code of lines.c https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-s096-introduction-to-c-and-c-january-iap-2013/final-project/starter-kit/lines.c and to have more context of where the source code is used you might want to see here https://ocw.mit.edu/courses/electrical-engineering-and-computer-science/6-s096-introduction-to-c-and-c-january-iap-2013/final-project/starter-kit/

If I run gcc without the option -E actually I get a linking problem because of my folder structure but the command below will work with no error -but I do not think this information was relevant for the question because I want to compare like for like and option -E stops after preprocessing and cpp does only preprocessing:

gcc -I/usr/local/libpng-1.6.24/include -L/usr/local/libpng-1.6.24/lib -Wall -std=c99 lines.c -lpng -o lines

--

I have upgraded my Xcode from 7.3 to 8.2.1 and the command line tools from Command_Line_Tools_OS_X_10.11_for_Xcode_7.3 to Command_Line_Tools_macOS_10.12_for_Xcode_8.2 and gcc continues working and cpp still triggering an error. Bu tthis time the error changes a little bit. See below

In file included from lines.c:1:
In file included from /usr/include/stdio.h:65:
In file included from /usr/include/Availability.h:184:
/usr/include/AvailabilityInternal.h:20265:10: error: #else without #if
    #else
/usr/include/AvailabilityInternal.h:20832:10: error: unterminated conditional directive
    #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11_4

Upvotes: 3

Views: 5037

Answers (2)

zwol
zwol

Reputation: 140455

I don't appear to have exactly the same AvailabilityInternal.h on my Mac as either user2353698 or Jonathan Leffler does, but I can still reproduce the problem:

$ /usr/bin/cpp -w /usr/include/AvailabilityInternal.h > /dev/null
/usr/include/AvailabilityInternal.h:14923:10: error: #else without #if
        #else
         ^

With some help from the insanely handy delta utility I have cut it down to a minimized test case:

#ifndef foo
    #ifdef bar
    #endif
#endif

This is perfectly legal standard C, but the traditional (K&R) preprocessor would not have understood either of the indented lines as preprocessing directives. clang's emulation of traditional preprocessing mode appears to have a bug, in which the indented #ifdef is not processed but the indented #endif is processed, so the subsequent non-indented #endif appears to be unbalanced. (Compare the behavior of gcc -E -traditional-cpp on this file, on a computer where gcc is actually GCC.) This has now been reported as LLVM bug #31886.

What I said in comments yesterday is still true: if you want to preprocess standard C, use cc -E. Even without this bug, cpp would not give the correct result on these system headers. It is intentional that cpp uses traditional mode, because the primary function of that command line tool nowadays is to preprocess things that are not C, such as FORTRAN, Makefiles, and X resources files. The traditional preprocessor is better suited to this task, as it is not as specialized for C's lexical syntax.

Upvotes: 1

Jonathan Leffler
Jonathan Leffler

Reputation: 753505

As noted in the comments, I can reproduce your problem on my macOS Sierra 10.12.3 machine with XCode 8, getting (at least) 20 errors so it stops on the 20th.

Source file:

#include <stdio.h>
int main(void) { puts("Hi"); return 0; }

Command line and error output:

$ /usr/bin/cpp -v min.c -o min.c.out >/dev/null
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -E -disable-free -disable-llvm-verifier -discard-value-names -main-file-name min.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 274.2 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0 -fdebug-compilation-dir /Users/jleffler/soq -ferror-limit 19 -fmessage-length 110 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -traditional-cpp -o - -x c min.c
clang -cc1 version 8.0.0 (clang-800.0.42.1) default target x86_64-apple-darwin16.4.0
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
In file included from min.c:1:
In file included from /usr/include/stdio.h:65:
In file included from /usr/include/Availability.h:184:
/usr/include/AvailabilityInternal.h:20265:10: error: #else without #if
        #else
         ^
/usr/include/AvailabilityInternal.h:20832:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11_4
         ^
/usr/include/AvailabilityInternal.h:20765:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11_3
         ^
/usr/include/AvailabilityInternal.h:20702:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11_2
         ^
/usr/include/AvailabilityInternal.h:20643:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_11
         ^
/usr/include/AvailabilityInternal.h:20588:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10_3
         ^
/usr/include/AvailabilityInternal.h:20537:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10_2
         ^
/usr/include/AvailabilityInternal.h:20490:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_10
         ^
/usr/include/AvailabilityInternal.h:20447:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_9
         ^
/usr/include/AvailabilityInternal.h:20408:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_8
         ^
/usr/include/AvailabilityInternal.h:20373:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_7
         ^
/usr/include/AvailabilityInternal.h:20342:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_6
         ^
/usr/include/AvailabilityInternal.h:20315:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_5
         ^
/usr/include/AvailabilityInternal.h:20292:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_4
         ^
/usr/include/AvailabilityInternal.h:20273:10: error: unterminated conditional directive
        #if __MAC_OS_X_VERSION_MIN_REQUIRED >= __MAC_10_3
         ^
In file included from min.c:1:
In file included from /usr/include/stdio.h:65:
/usr/include/Availability.h:233:2: error: #else without #if
#else
 ^
/usr/include/Availability.h:236:2: error: #endif without #if
#endif
 ^
/usr/include/Availability.h:272:2: error: #endif without #if
#endif
 ^
/usr/include/Availability.h:299:2: error: #endif without #if
#endif
 ^
fatal error: too many errors emitted, stopping now [-ferror-limit=]
20 errors generated.
$

Note that the only options I used were -v (to produce the verbose output at the start) and -o min.c.out (which is over-ridden with -o - in the verbose output; it did as it wanted rather than as I told it to do — rank insubordination, really). The redirection of standard output to /dev/null was necessary to avoid seeing all the output, therefore.

If I replace /usr/bin/cpp with /usr/bin/gcc (the path is necessary for me since gcc is /opt/gcc/v6.2.0/bin/gcc, aka GCC 6.2.0), and I add the -E option, it works fine:

$ /usr/bin/gcc -E -v min.c -o min.c.out
Apple LLVM version 8.0.0 (clang-800.0.42.1)
Target: x86_64-apple-darwin16.4.0
Thread model: posix
InstalledDir: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin
 "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang" -cc1 -triple x86_64-apple-macosx10.12.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -E -disable-free -disable-llvm-verifier -discard-value-names -main-file-name min.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -target-linker-version 274.2 -v -dwarf-column-info -debugger-tuning=lldb -resource-dir /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0 -fdebug-compilation-dir /Users/jleffler/soq -ferror-limit 19 -fmessage-length 110 -stack-protector 1 -fblocks -fobjc-runtime=macosx-10.12.0 -fencode-extended-block-signature -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -o min.c.out -x c min.c
clang -cc1 version 8.0.0 (clang-800.0.42.1) default target x86_64-apple-darwin16.4.0
#include "..." search starts here:
#include <...> search starts here:
 /usr/local/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/../lib/clang/8.0.0/include
 /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include
 /usr/include
 /System/Library/Frameworks (framework directory)
 /Library/Frameworks (framework directory)
End of search list.
$ wc -l min.c.out
     456 min.c.out
$

This strongly hints at a problem of some sort in the /usr/bin/cpp program and the way it drives the rest of the compilation tool chain, but I've not identified the crucial difference in the command line.

It also hints at a solution — don't use cpp standalone. As I noted in comments, there was a question from January 2017 — How to get XCode 8 C preprocessor to ignore // comments in #defines? that also pointed to a problem in the standalone cpp.

If you must have a working cpp, then install your own. For example, you could install GCC 6.3.0 (I've been lazy on this machine; my other one is already running 6.3.0, not 6.2.0) in some location (e.g. /opt/gcc/v6.3.0/bin/cpp) and then arrange for that to be run instead of /usr/bin/cpp when you type cpp — adjust PATH, or put a symlink or script in a directory such as /usr/local/bin or $HOME/bin that occurs on PATH before /usr/bin, or specify the correct PATH in the makefile, or whatever it takes.

If you want guidelines on building GCC on a Mac, consider:

Upvotes: 2

Related Questions