me icon indicating copy to clipboard operation
me copied to clipboard

Swift & C (Part 0)

Open nonocast opened this issue 2 years ago • 0 comments

还没想好,先记录

  • linux c通过ar将.o生成lib,macOS需要通过libtool -static -o libxxx xxx.o
  • 在Xcode中,将arm64的lib复制到项目目录中,会自动添加到target的library中,也可以直接添加外部library
  • 然后需要在bridge header中增加c definition,或者直接将lib的header复制到项目中,然后在bridge中引用
  • 从swift到c还是会很曲折,比如需要用到pointer,然后不支持可变参数等等兼容性问题,所以需要通过package或者framework做一层转换,提供给swift调用方native的接口,就是在swift和c lib中做一个转换层

Mach-O

  • Mach-O是Mach Object文件格式的缩写,等同于Windows上的PE,Linux上的elf
  • Object file: .o
  • Library: .a, .dylib, .Framework
  • Executable file

foo.c

int biubiubiu(void) { return 666; }

通过clang -c foo.c就可以生成object file

➜  clang -c foo.c
➜  file foo.o
foo.o: Mach-O 64-bit object x86_64
➜  nm foo.o 
0000000000000000 T _HUI_Version
➜  lipo -info foo.o
Non-fat file: foo.o is architecture: x86_64

ok,我们可以分别单独编译出arm64和x86_64的object file,然后通过lipo打成一个fat binary

➜  clang -c -arch arm64 -o foo.o.arm64 foo.c
➜  clang -c -arch x86_64 -o foo.o.x86_64 foo.c
➜  lipo foo.o.arm64 foo.o.x86_64 -create -output foo.o
➜  libtool -static -o libfoo.a foo.o
➜    
➜  file foo.o
foo.o: Mach-O universal binary with 2 architectures: [x86_64:Mach-O 64-bit object x86_64Mach-O 64-bit object x86_64] [arm64:Mach-O 64-bit object arm64Mach-O 64-bit object arm64]
foo.o (for architecture x86_64):        Mach-O 64-bit object x86_64
foo.o (for architecture arm64): Mach-O 64-bit object arm64
➜  lipo -info libfoo.a 
Architectures in the fat file: libfoo.a are: x86_64 arm64 
➜  lipo -archs libfoo.a 
x86_64 arm64

对应的Makefile

all: libfoo.a

foo.o.arm64: foo.c
	clang -c -arch arm64 -o $@ $<

foo.o.x86_64: foo.c
	clang -c -arch x86_64 -o $@ $<

foo.o: foo.o.arm64 foo.o.x86_64
	lipo $^ -create -output $@

libfoo.a: foo.o
	libtool -static -o $@ $^

clean:
	rm *.a *.o*

.PHONY: all clean

更新May 22: BigNerd书p57: gcc -arch arm64 -arch x86_64 app.c可以直接生成fat binary.

Framework

  • Frameworks are packaged in bundle structure, 后缀采用.framework
  • 分为standard frameworks和umbrella frameworks. umbrella frameworks比标准的高级一点,支持包含其他框架等额外的特性
  • Layout
    • MyFramework.framework/
      • MyFramework -> Versions/Current/MyFramework
      • Resources -> Versions/Current/Resources
      • Versions/
        • A/ :MyFramework, Resources
        • B/ :MyFramework, Resources
        • Current -> B

不清楚的花,直接去看下xcrun --show-sdk-path下系统的framework,交叉比对一下。

所以,如果是需要vscode的方式,则需要手动建立目录和link,然后对整个目录进行code sign

  • app bundle参考: #238
  • code sign参考: #212
  • code sign是针对foo.framework, 而不是里面的lib
  • libfoo.a放到framework后需要命名为foo,和framework的name一致
  • 必须要有Resources/Info.plist, 这个直接从Xcode framework复制出来就行
  • 如果格式有问题,在codesign会提示错误

使用时,

  • 新建macOS SwiftUI项目
  • 新建一个.c,目的是为了引入Bridging-Header
  • 在target中添加framework
  • 如果framework不在系统framework path中,则需要在building/Search Paths中指定Framework Search Paths
  • 然后添加Header Search Paths,和framework一致
  • 最后在Bridging-Header中添加header files

Test-Bridging-Header

#import <foo/foo.h>
  • framework本质上就是对资源的package,1来解决了version,2来解决了header, libs散落在全局路径上,还是为了安全。

SwiftPM

Command Tools

  • clang
  • lipo
  • libtool
  • otool
  • nm

参考文档

nonocast avatar May 21 '22 01:05 nonocast