I'm trying to create an xcframework around some existing C code we have, wrap that in a Swift Package, and then create a sample app using that package. One of our C headers includes iso646.h (among other C system headers), it's used like this:
#if defined(__ANDROID__) or defined(__iOS__)
and errors out with:
Token is not a valid binary operator in a preprocessor subexpression
when building the sample app, on the or in that line (with other similar errors on similar lines).
I think I need to somehow let my app know it needs to pull in the iso646 header file. I tried with a module map that gets included with the xcframework, by adding link "iso646" in my framework module. I also tried to create a separate module at the top level, in that same module map, with:
Neither of these approaches worked; we kept getting the same error.
My next attempt was to create a Swift Library Package that just wrapped some C system libraries, but I got stuck because I didn't see a way to include that as a dependency on the binaryTarget for my xcframework in my Swift Package.
I've been stuck on this a while, and I'm hoping this newbie is just missing something pretty basic; how can I past this error?
P.S. This is a cross-post from Stack Overflow; I wasn't getting any help there.
Thank you, but do you have any idea why Swift doesn't recognize the symbols defined in iso646.h in this context? I'm trying to figure out if I'm doing something wrong or if this just isn't supported.
Oh, I got your point. There is #define and && in iso646.h. And when the header is included, we can use #if A and B in a .m or .c file. But here we will have problem when using it in a header.
You can copy the contents of iso646.h directly into your header - Minimis.h. And that’s how a #include directive works.
Here is what I found:
If we do not change the content, it will be the same as if we still use #include "iso646.h". And the build will fail.
By modifying #ifndef __ISO646_H to something else, it will be valid to use and in the header.
// Minimis.h
#import <Foundation/Foundation.h>
FOUNDATION_EXPORT double MinimisVersionNumber;
FOUNDATION_EXPORT const unsigned char MinimisVersionString[];
#ifndef __ISO646_H2
#define __ISO646_H2
#ifndef __cplusplus
#define and &&
#endif
#endif
#if A and B
#pragma message ("A and B are defined")
#else
#warning Neither A nor B are defined
#endif
void f(void);
Therefore, it seems that the __ISO646_H has been defined when processing this file. So I update it to the following to try to find where is the previous define.
Oh no There’s not much more context beyond what’s written there: some system headers use either and or or as an identifier (don’t remember which). What I’m not sure about is why modules aren’t sufficient to fix this: the headers that use and and or wouldn’t be including iso646.h. Maybe someone at Apple can go find the specific motivating example for that change, because maybe it’s been fixed.
We still have to be very careful about changing this though, because perhaps Library A included iso646.h without using it, and Swift bridging header B imports library A and uses one of the reserved words as an identifier. So we might just be stuck for source compatibility reasons.
Unfortunately language modes cannot easily be used to adjust the importer, because all imported Swift modules need to have the same (or at least compatible) views of imported Clang modules, and you can mix and match Swift versions across modules.