cswiftswift-package

Swift package C header errors


My C library compiles and gets packaged into an xcframework without a problem, but my Swift project that uses this through a Swift Package then has some errors...

Namely, I'm getting

Token is not a valid binary operator in a preprocessor subexpression

This error shows up, for example, for the or in #if defined(__ANDROID__) or defined(__iOS__).

This header file has #include <iso646.h> (which defines or), and I tried #include "iso646.h" for if SWIFT_PACKAGE, but that didn't help. I also tried to hard-code the contents of this system header into my header, without luck.

Why is my Swift project choking on these?

Edit:

I tried a minimal reproducible example, and I get the same error message.

Here's the code:

Minimis.c:

#include "stdio.h"
void f(void) {
  printf("f called from within xcframework");
}

Minimis.h:

#import <Foundation/Foundation.h>

//! Project version number for Minimis.
FOUNDATION_EXPORT double MinimisVersionNumber;

//! Project version string for Minimis.
FOUNDATION_EXPORT const unsigned char MinimisVersionString[];

// In this header, you should import all the public headers of your framework using statements like #import <Minimis/PublicHeader.h>

#include "iso646.h"
#if A and B
    #pragma message ("A and B are defined")
#else
    #warning Neither A nor B are defined
#endif

void f(void);

Creating an xcframework and a Swift Package from that causes the failure on the #if A and B header line when trying to use the Swift Package in a Swift Project.

I tried modifying the module.modulemap file that gets included with my xcframework to include the iso646 header, like:

framework module Minimis {
  umbrella header "Minimis.h"

  export *
  module * { export * }
  
  link "iso646"
}

... but that doesn't resolve the error. I also tried to create a Swift Package Library that just wraps some C standard libraries, but then I didn't see how to include that in my other Swift Package (I'm using a binary target to pull in my xcframework, and the binaryTarget method doesn't take dependencies).


Solution

  • After checking the content of <iso646.h>, I found that and is defined here.

    And using some trick I found __ISO646_H was already defined in command line to deliberately prevent someone from using it.

    The code is here and only Apple will know why.

    https://github.com/apple/swift/blob/c251b3cf56ab107480a8fb1149a788aa101d29e2/lib/ClangImporter/ClangImporter.cpp#L556

    Reply from pre-Apple employees https://forums.swift.org/t/including-c-system-headers-through-a-swift-package/66543/7