Rui*_*Rui 8 ncurses swift swift-package-manager
我正在尝试使用Swift Package Manager在库中使用ncurses,我想使用ncurses的特定版本,而不是OS X中包含的版本。为此,我使用Homebrew安装了最新版本(6.1)。这是我的Package.swift样子:
// swift-tools-version:5.0
import PackageDescription
let package = Package(
name: "NcursesExample",
products: [
.executable(name: "NcursesExample", targets: ["NcursesExample"]),
],
dependencies: [
],
targets: [
.systemLibrary(name: "Cncurses"),
.target(name: "NcursesExample", dependencies: ["Cncurses"]),
]
)
Run Code Online (Sandbox Code Playgroud)
在Sources目录下,我有一个Cncurses的子目录,其中包含module.modulemap和shim.h文件:
module.modulemap
module Cncurses {
header "shim.h"
link "ncurses"
export *
}
Run Code Online (Sandbox Code Playgroud)
希姆
#include "/usr/local/Cellar/ncurses/6.1/include/ncurses.h"
Run Code Online (Sandbox Code Playgroud)
但是,在编译时,我遇到几个错误,抱怨类型冲突,这显然是因为macOS SDK还提供了ncurses:
shim.h:1:10: note: in file included from shim.h:1:
#include "/usr/local/Cellar/ncurses/6.1/include/ncurses.h"
^
/usr/local/Cellar/ncurses/6.1/include/ncurses.h:60:10: error: 'ncursesw/ncurses_dll.h' file not found with <angled> include; use "quotes" instead
#include <ncursesw/ncurses_dll.h>
^
<module-includes>:1:9: note: in file included from <module-includes>:1:
#import "shim.h"
^
shim.h:1:10: note: in file included from shim.h:1:
#include "/usr/local/Cellar/ncurses/6.1/include/ncurses.h"
^
/usr/local/Cellar/ncurses/6.1/include/ncurses.h:674:45: error: conflicting types for 'keyname'
extern NCURSES_EXPORT(NCURSES_CONST char *) keyname (int); /* implemented */
^
/Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.14.sdk/usr/include/curses.h:598:45: note: previous declaration is here
extern NCURSES_EXPORT(NCURSES_CONST char *) keyname (int); /* implemented */
...
Run Code Online (Sandbox Code Playgroud)
我正在尝试使用以下方法编译软件包:
swift build -Xcc -I/usr/local/Cellar/ncurses/6.1/include/ -Xlinker -L/usr/local/Cellar/ncurses/6.1/lib
我也遵循了pkgConfig在包定义中指定的方法,结果相同。有人可以帮忙吗?
仅供参考,值得一提的是,通过Homebrew安装ncurses时,由于OS X已经提供了ncurses,我会收到以下警告:
ncurses is keg-only, which means it was not symlinked into /usr/local,
because macOS already provides this software and installing another version in
parallel can cause all kinds of trouble.
If you need to have ncurses first in your PATH run:
echo 'export PATH="/usr/local/opt/ncurses/bin:$PATH"' >> ~/.zshrc
For compilers to find ncurses you may need to set:
export LDFLAGS="-L/usr/local/opt/ncurses/lib"
export CPPFLAGS="-I/usr/local/opt/ncurses/include"
For pkg-config to find ncurses you may need to set:
export PKG_CONFIG_PATH="/usr/local/opt/ncurses/lib/pkgconfig"
Run Code Online (Sandbox Code Playgroud)
用于ncurses的Pkgconfig看起来像这样
# pkg-config file generated by gen-pkgconfig
# vile:makemode
prefix=/usr/local/Cellar/ncurses/6.1
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include/ncursesw
abi_version=6
major_version=6
version=6.1.20180127
Name: ncursesw
Description: ncurses 6.1 library
Version: ${version}
URL: https://invisible-island.net/ncurses
Requires.private:
Libs: -L${libdir} -lncursesw
Libs.private:
Cflags: -D_DARWIN_C_SOURCE -I/usr/local/Cellar/ncurses/6.1/include -I${includedir}
Run Code Online (Sandbox Code Playgroud)
问题
主要问题是头文件的冲突,因为 /Applications/Xcode.app/.../MacOSX10.14.sdk/usr/include 中也提供了 ncurses。
在这种情况下,常见的纯 C 解决方案是仅使用 -I 分别 -L 指定自定义 include 和 lib 目录,它会起作用,请参阅我关于 C ncurses 的答案:https: //stackoverflow.com/a/56623033/2331445
这种方法似乎不适用于 Swift 包管理器。但这并不意味着只需付出一点努力就不可能实现。
可能的解决方案
我们需要确保忽略 macOS SDK 提供的 ncurses 头文件。我们可以通过为 swift build 命令指定 -Xcc -D__NCURSES_H 参数来完成此操作。
这是有效的,因为在头文件中,有这样的典型:
#ifndef __NCURSES_H
#define __NCURSES_H
...
#endif
Run Code Online (Sandbox Code Playgroud)
当然,问题是我们使用 Brew 自定义安装的 ncurses 也会受到影响。但我们可以解决这个问题:
#include <ncursesw/unctrl.h>使用例如而不是形式“#include“ncursesw/unctrl.h””这实际上可以通过以下命令行命令来完成:
cd Sources/Cncurses
cp -r /usr/local/Cellar/ncurses/6.1/include include
find . -name '*.h' -exec sed -i '' 's/__NCURSES_H/__CNCURSES_H/g' {} \;
find . -name '*.h' -exec sed -i '' -E -e "s/<(.*(`find . -name '*.h' -exec basename {} \; | paste -sd "|" -`))>/\"\1\"/g" {} \;
Run Code Online (Sandbox Code Playgroud)
最后的陈述可能需要一些解释。借助 echo 命令,您可以查看生成的 sed 表达式,即如果执行
echo "s/<(.*(`find . -name '*.h' -exec basename {} \; | paste -sd "|" -`))>/\"\1\"/g"
Run Code Online (Sandbox Code Playgroud)
你会得到以下输出:
s/<(.*(termcap.h|form.h|term.h|panel.h|ncurses.h|termcap.h|cursesp.h|cursesf.h|etip.h|form.h|cursesw.h|nc_tparm.h|unctrl.h|cursesapp.h|term.h|cursslk.h|panel.h|ncurses.h|tic.h|eti.h|ncurses_dll.h|term_entry.h|menu.h|cursesm.h|curses.h|curses.h|cncurses.h))>/"\1"/g
Run Code Online (Sandbox Code Playgroud)
如您所见,它仅搜索并替换本地可用的包含文件。
测试
为了进行测试,我们需要一个简单的 ncurses 示例程序。应该构建它,并且我们应该确保使用正确版本的库。
模块.模块映射
我的头文件名为 cncurses.h。module.modulemap 看起来像这样:
module cncurses [system]
{
umbrella header "cncurses.h"
link "ncurses"
export *
}
Run Code Online (Sandbox Code Playgroud)
cncurses.h
cncurses.h 是一个单行程序,它从本地包含文件夹导入我们复制和定制的 ncurses.h 文件:
#include "include/ncurses.h"
Run Code Online (Sandbox Code Playgroud)
main.swift
在 NcursesExample 文件夹中,我们有 main.swift,其中有一个简单的 cncurses swift 应用程序:
import cncurses
initscr()
curs_set(0)
move(5, 10)
addstr("NCURSES")
move(10, 10)
addstr("Hello World!")
refresh()
select(0, nil, nil, nil, nil)
Run Code Online (Sandbox Code Playgroud)
包.swift
请注意此处的pkgConfig: "ncurses"系统库目标:
// swift-tools-version:5.0
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "NcursesExample",
dependencies: [
],
targets: [
.systemLibrary(name: "cncurses", pkgConfig: "ncurses"),
.target(name: "NcursesExample", dependencies: ["cncurses"]),
.testTarget(
name: "NcursesExampleTests",
dependencies: ["NcursesExample"]),
]
)
Run Code Online (Sandbox Code Playgroud)
建造
为了使 pkg-config 正确完成其工作,我们必须首先调用以下命令:
export PKG_CONFIG_PATH="/usr/local/opt/ncurses/lib/pkgconfig"
Run Code Online (Sandbox Code Playgroud)
最后我们启动构建:
swift build -Xcc -D__NCURSES_H
Run Code Online (Sandbox Code Playgroud)
因此,首先我们应该测试是否使用了正确的 ncurses 库。我们可以通过以下方式做到这一点:
otool -L .build/x86_64-apple-macosx/debug/NcursesExample
Run Code Online (Sandbox Code Playgroud)
除其他行外,输出还包含以下内容:
/usr/local/opt/ncurses/lib/libncursesw.6.dylib (compatibility version 6.0.0, current version 6.0.0)
Run Code Online (Sandbox Code Playgroud)
这看起来很有希望。
最后调用二进制文件:
Xcode项目
如果要生成Xcode项目,请使用以下命令:
swift package generate-xcodeproj
Run Code Online (Sandbox Code Playgroud)
然后在 Xcode 中加载项目并
| 归档时间: |
|
| 查看次数: |
525 次 |
| 最近记录: |