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

时间:2016-04-12 10:25:40

标签: c linux swift swift2

有没有办法编译本机C或C ++代码并将其暴露给Linux上的Swift?我可以看到像libdispatch这样的几个Apple库是用纯C编写的,只要导入它们就可以在Swift中访问它们。

要设置示例,我们假设我有两个文件Car.cCar.h来定义名为Car的结构。有没有办法可以编译它们并通过编写import语句在Swift中使用它们?

import Car

我尝试在module.modulemap.c.h文件所在的目录中编写Package.swift个文件:

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

并运行swift build。这个产量错误:

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

我使用的是Swift 3.0-dev版本(2016年3月24日)

[更新1]

我联系了Max(mxcl) - Swift Package Manager的创建者之一,他告诉我要删除modulemap并放置.c.h个文件直接在Sources文件夹中。我编译完这个包后,但它不能用作模块。此外,我无法调用.h文件中的任何已定义函数。

2 个答案:

答案 0 :(得分:13)

如果您使用C代码构建库,则可以为其创建系统模块,然后可以将其导入Swift,请参阅以下答案:Use a C library in Swift on Linux

另一种处理此任务的方法是创建一个桥接标头,如@Philip所建议的那样。这是一个简单的例子。我们考虑以下C代码:

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

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

我们将使用car.h作为桥接头。 swift源是(在文件junk.swift中):

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

首先,从car.o

创建一个目标文件car.c
gcc -c car.c

现在构建一个可执行文件junk,如下所示:

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

运行可执行文件会给出:

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

隐藏了-import-objc-header选项。要查看它和一些其他隐藏选项,请运行:

swiftc -help-hidden 

我是从4月12日开始使用Swift 3.0开发快照为Ubuntu 14.04做的,可在此处找到:https://swift.org/builds/development/ubuntu1404/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a/swift-DEVELOPMENT-SNAPSHOT-2016-04-12-a-ubuntu14.04.tar.gz

现在,如果你想使用C ++,你需要创建一个包装器,用C ++源文件编写并用C ++编译器编译,但使用extern "C"从C调用的函数。然后可以从Swift中调用这些函数作为任何C函数。例如,请参阅此答案:Can I mix Swift with C++? Like the Objective - C .mm files

答案 1 :(得分:4)

在swift中使用C函数需要一个桥接头,其中包含您需要的所有C功能。例如,myBridgingHeader.h包含#include&#34; Car.h&#34;以及您想要的任何其他C内容。我相信目前不支持C ++。

一旦你有了桥接头,你需要迅速了解它。 Xcode用户在将其添加到项目中时可以免费获得。在Linux中,使用&#39; -import-objc-header / path / to / header&#39;编译时标记。

编辑:我已经在下面添加了一个完整的示例,其中包含6个文件,供其他可能有此问题的人使用。它与上面的基本相同,但我没看到直到我把它放在一起哈哈。此外,它可能对需要链接静态库的人有用。

将下面的文件内容复制到具有适当名称的文件make,然后./hello,这应该可行。为了记录,我只在swift版本2.2-dev上运行它(使用swift --version来检查你的)

  • hello.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:

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

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

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

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

    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