Importing a Swift module using a C library

2020-04-21 09:10发布

问题:

I've written a Curses wrapper module by following the instructions of this page.

However, I do not know how to properly make it work in a module using it.

I have 3 parallel directories: CCurses, CursesWrapper, ModuleUsingCursesWrapper.

CCurses contains an empty Package.swift file and a module.modulemap file containing

module CCurses [system] {
    header "/usr/include/curses.h"
    link "curses"
    export *
}

CursesWrapper contains a Package.swift file containing.

import PackageDescription

let package = Package(dependencies: [.Package(url: "../CCurses", majorVersion: 1)])

and a general.swift file containing

import CCurses

public func startCurses() -> Void{
    initscr()}

public func getchar() -> Void{
    getch()}

public func endCurses() -> Void{
    endwin()}

ModuleUsingCursesWrapper contains a Package.swift file containing

import PackageDescription

let package = dependencies: [.Package(url: "../CursesWrapper", majorVersion: 1)])

and a main.swift file containing

import CursesWrapper

startCurses()
getchar()
endCurses()

When running swift build in ModuleUsingCursesWrapper, I get the following output:

Cloning Packages/CursesWrapper
Cloning Packages/CCurses
Compiling Swift Module 'CursesWrapper' (1 sources)
Linking Library:  .build/debug/CursesWrapper.a
Compiling Swift Module 'ModuleUsingCursesWrapper' (1 sources)
Linking Executable:  .build/debug/ModuleUsingCursesWrapper
.../ModuleUsingCursesWrapper/.build/debug/CursesWrapper.a(general.swift.o): In function `_TF14CursesWrapper11startCursesFT_T_':
.../ModuleUsingCursesWrapper/Packages/CursesWrapper-1.0.0/general.swift:5: undefined reference to `initscr'
.../ModuleUsingCursesWrapper/.build/debug/CursesWrapper.a(general.swift.o): In function `_TF1CursesWrapper7getcharFT_T_':
.../ModuleUsingCursesWrapper/Packages/CursesWrapper-1.0.0/general.swift:8: undefined reference to `getch'
.../ModuleUsingCursesWrapper/.build/debug/CursesWrapper.a(general.swift.o): In function `_TF14CursesWrapper9endCursesFT_T_':
.../ModuleUsingCursesWrapper/Packages/CursesWrapper-1.0.0/general.swift:11: undefined reference to `endwin'
clang: error: linker command failed with exit code 1 (use -v to see invocation)
< unknown >:0: error: link command failed with exit code 1 (use -v to see invocation)
< unknown :0: error: build had 1 command failures
swift-build: exit(1): [".../Swift/usr/bin/swift-build-tool", "-f", ".../ModuleUsingCursesWrapper/.build/debug/ModuleUsingCursesWrapper.o/llbuild.yaml"]

It seems that when compiling ModuleUsingCursesWrapper, the curses functions cannot be found. How can I solve this problem ?

(I'm on Linux)

回答1:

After playing with your example for awhile on an Ubuntu 14.04 box, I ran into the same error. After some additional experimentation, I was able to solve it by adding the following to main.swift:

import CCurses

The Package.swift file of the module using the wrapper references only CursesWrapper, but if CCurses is not imported into main.swift, then the undefined reference error occurs.

The need to import dependencies of imported modules can be seen from the link to swift.org that you provided, where a JasPer/JPEG example is discussed. Strictly speaking, JasPer is not a wrapper around JPEG, but is just another system module, yet the idea is the same: if we import module A that depends on module B, then we should also import module B.

BTW I had to change public func getchar() to public func getChar() and modify main.swift accordingly. Otherwise I would get ambiguous use of 'getchar()' error when compiling main.swift. Evidently it is already defined in CCurses, which is no surprise as it is a standard C function.