How to import Swift function into C while using 'swiftc' only?

Hi. I can easily import C code into my Swift code and compile it with something like this (from basic.c into main.swift):

swiftc main.swift basic.c -import-objc-header basic.h

However, I can not figure out how to do the opposite. How do I import a function defined in main.swift into the basic.c?

Thank you.

1 Like

Generate a header and import that: Is there a way to emit C/C++ header? - #3 by ole

Thanks. While it works, it also breaks in some other ways (which is confusing). It can no longer find a function declared in C.

Let's say I have the following 3 files:

// basic.c
#include "basic.h"
#include "main.h"

void hello() {
    printf("Hello, C!\n");
    doSomething();
}

// basic.h
#ifndef basic_h
#define basic_h

#include <stdio.h>

void hello();

#endif /* basic_h */

// main.swift
@_cdecl("doSomething")
public func doSomething() {
    print("something")
}

print("Hello, Swift!")
hello()

What will be the right combination of commands to build main executable (main.swift is an entry point, of course)?

1 Like

If you rename basic.c to basic.m, making this a mixed Swift-ObjC target, this works for me on macOS 15.0 with Xcode 16.0 (Swift 6.0):

$ swiftc -import-objc-header basic.h \
      -emit-clang-header-path main.h \
      main.swift basic.m
$ ./main
Hello, Swift!
Hello, C!
something

Sorry if this doesn't help you, but I found it interesting.

1 Like

You know what? I just tried that, and it worked like a charm!!!! Thanks. But it refuses to work with .c extension…

What is going on!? I am so confused. :slight_smile:

1 Like

I don't know.

This recent post seems relevant: Is there a way to list the APIs provided by my dynamic library?. It seems to suggest that the emitted header contains Obj-C-specific features. (The OP speaks of -emit-objc-header-path, not -emit-clang-header-path, but in my testing both flags emit the same C header, at least when C++ interop is not enabled. I haven't tried it with C++ interop.)

Another fun fact. I have added -cxx-interoperability-mode=default flag, left basic.c and main.swift files as is and updated my basic.h to:

#ifndef basic_h
#define basic_h

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>

void hello();

#ifdef __cplusplus
}
#endif

#endif

and it worked!

Here is my current command:

swiftc -import-objc-header basic.h -emit-clang-header-path main.h main.swift basic.c -cxx-interoperability-mode=default
3 Likes