简体   繁体   English

Linux下编译C代码并暴露给Swift

[英]Compile C code and expose it to Swift under Linux

Is there a way to compile native C or C++ code and expose it to Swift on Linux?有没有办法编译本机 C 或 C++ 代码并将其公开给 Linux 上的 Swift? I can see that several Apple libraries like libdispatch are written in pure C and that you can access them in Swift just by importing them.我可以看到像libdispatch这样的几个 Apple 库是用纯 C 编写的,您只需导入它们就可以在 Swift 中访问它们。

To set the example let's say that I have two files Car.c and Car.h that define structure named Car .举个例子,假设我有两个文件Car.cCar.h ,它们定义了名为Car结构。 Is there a way that I can compile them and use them in Swift by writing import statement?有没有办法通过编写导入语句来编译它们并在 Swift 中使用它们?

import Car

I've tried writing module.modulemap file inside directory where .c , .h and Package.swift files are located:我试过在.c.hPackage.swift文件所在的目录中编写module.modulemap文件:

module Car {
   header "Car.h"
   export *
}

and running swift build .并运行swift build This yield error:这个产量错误:

<unknown>:0: error: unexpected 'commands' value (expected map)
<unknown>:0: error: unable to load build file

I'm using Swift version 3.0-dev (March 24 2016)我正在使用 Swift 版本 3.0-dev(2016 年 3 月 24 日)

[Update 1] [更新1]

I've contacted Max(mxcl) - one of the creators of Swift Package Manager and he told me to get rid of the modulemap and put the .c and .h files directly in Sources folder.我已经联系了 Max(mxcl) - Swift Package Manager 的创建者之一,他告诉我摆脱modulemap并将.c.h文件直接放在Sources文件夹中。 After I did that package compiled but it's not available as module.在我编译了那个包之后,它不能作为模块使用。 Also I can't call any of the defined functions in the .h file.此外,我无法调用.h文件中的任何定义的函数。

If you build a library out of your C code, you can create a system module for it, which can then be imported into Swift, see this answer: Use a C library in Swift on Linux .如果您使用 C 代码构建一个库,则可以为其创建一个系统模块,然后将其导入 Swift,请参阅此答案: 在 Linux 上的 Swift 中使用 C 库

Another way to approach this task is to create a bridging header, as suggested by @Philip.处理此任务的另一种方法是创建一个桥接头,如@Philip 所建议的那样。 Here is an oversimplified example.这是一个过于简化的例子。 Let's consider the following C code:让我们考虑以下 C 代码:

/* In car.h */
int getInt();

/* In car.c */
int getInt() { return 123; }

We will use car.h as the bridging header.我们将使用 car.h 作为桥接头。 The swift source is (in file junk.swift ):快速来源是(在文件junk.swift ):

print("Hi from swift!")
var i = getInt()
print("And here is an int from C: \(i)!")

First, create an object file, car.o , from car.c :首先,创建一个目标文件, car.o ,从car.c

gcc -c car.c

Now build an executable, junk , as follows:现在构建一个可执行文件, junk ,如下:

swiftc -import-objc-header car.h junk.swift car.o -o junk

Running the executable gives:运行可执行文件给出:

$ ./junk
Hi from swift!
And here is an int from C: 123!

The -import-objc-header option is hidden. -import-objc-header选项被隐藏。 To see it and a bunch of other hidden options, run:要查看它和一堆其他隐藏选项,请运行:

swiftc -help-hidden 

I did this using Swift 3.0 development snapshot for Ubuntu 14.04 from April 12, available here: https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a-ubuntu14.04.tar.gz我从 4 月 12 日开始使用 Ubuntu 14.04 的 Swift 3.0 开发快照,可在此处获取: https : //swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a/swift-DEVELOPMENT- SNAPSHOT-2016-04-12-a-ubuntu14.04.tar.gz

Now, if you want to use C++, you will need to create a wrapper, written in a C++ source file and compiled with a C++ compiler, but with functions callable from C by using extern "C" .现在,如果您想使用 C++,您将需要创建一个包装器,用 C++ 源文件编写并使用 C++ 编译器编译,但可以使用extern "C"从 C 调用函数。 Those functions can then be called from Swift as any C function.然后可以像任何 C 函数一样从 Swift 调用这些函数。 See, for example, this answer: Can I mix Swift with C++?例如,请参阅此答案: 我可以将 Swift 与 C++ 混合使用吗? Like the Objective - C .mm files 像 Objective-C .mm 文件

Using C functions in swift requires a bridging header that includes all the C functionality you need.在 swift 中使用 C 函数需要一个包含所有你需要的 C 功能的桥接头文件。 For example, myBridgingHeader.h which contains #include "Car.h"and whatever other C stuff you want.例如, myBridgingHeader.h 包含 #include "Car.h" 以及您想要的任何其他 C 内容。 I believe C++ is currently not supported.我相信目前不支持 C++。

Once you have the bridging header you need to make swift aware of it.一旦你有了桥接头,你需要迅速意识到它。 Xcode users get this for free when they add it to the project. Xcode 用户在将它添加到项目时可以免费获得它。 In Linux, use '-import-objc-header /path/to/header' flag when compiling.在 Linux 中,编译时使用 '-import-objc-header /path/to/header' 标志。

Edit: I've added a complete example below consisting of 6 files for any others who may have this question.编辑:我在下面添加了一个完整的示例,其中包含 6 个文件,供可能有此问题的任何其他人使用。 It's basically the same as the one above but I didn't see that til I had already put it together haha.基本上和上面那个一样,但是我没有看到,直到我已经把它放在一起了哈哈。 Also, it maybe useful for someone who needs to link against static libraries.此外,它可能对需要链接静态库的人有用。

Copy the file contents below to appropriately named files, make , then ./hello and that should work.将下面的文件内容复制到适当命名的文件中, make ,然后是./hello ,这应该可以工作。 For the record, I've only run this on swift version 2.2-dev (use swift --version to check yours)作为记录,我只在 swift 版本 2.2-dev 上运行它(使用swift --version检查你的)

  • hello.swift:你好.swift:

     let n: Int32 = 5 print("Hello, Swift World!") print("mult2(\\(n,N)) = \\(mult2(n,N))") print("CONST1=\\(CONST1), CONST2=\\(CONST2), CONST3=\\(CONST3)")
  • bridge.h:桥接.h:

     #include "defs.h" #include "mult.h"
  • defs.h: defs.h:

     #define CONST1 1 #define CONST2 2 #define CONST3 3
  • mult.h:多小时:

     #define N 7 int mult2(int,int);
  • mult.c:多c:

     #include "defs.h" #include "mult.h" int mult2(int a, int b) { return a*b; }
  • Makefile:生成文件:

     all: hello hello: libmult.a swiftc hello.swift -import-objc-header ./bridge.h -L. -lmult -o hello libmult.a: mult.o ar -rc libmult.a mult.o ranlib libmult.a mult.o: mult.c mult.h defs.h gcc -c mult.c -o mult.o .PHONY: clean clean: rm -f *.o *.a hello

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM