I hava a Swift Package with an executable target, the project structure looks like this:
MySwiftPackage
├── Package.swift
├── Sources
│ └── MySwiftPackage
│ ├── SwiftBridgeCore.swift
│ ├── main.swift
│ └── my_rust_lib.swift
├── bridging-header.h
├── file.json
├── generated
│ ├── SwiftBridgeCore.h
│ └── my_rust_lib
│ └── my_rust_lib.h
└── lib_mac
└── libmy_rust_lib.a
This package needs to link to the static library lib_mac/libmy_rust_lib.a and links with the bridging-header.h.
The bridging-header.h just has some #include to the headers in generated.
To build this project, I run
swiftc -L lib_mac -lmy_rust_lib \
-import-objc-header bridging-header.h \
Sources/LinuxSwiftPackage/*.swift
This will build an executable I can run. I now want to accomplish the same this using swift build, so that I can add dependencies.
I have tried the following:
1. In my Package.swift, I added the following:
let package = Package(
name: "MySwiftPackage",
dependencies: [],
targets: [
.executableTarget(
name: "MySwiftPackage",
dependencies: [],
cSettings: [
.headerSearchPath(".")
],
linkerSettings: [
.linkedLibrary(":lib_mac/libmy_rust_lib.a")
]
)
]
)
This did not link the library however, as I got a lot of cannot find type <SomeType defined in the header> in scope
2. I have added the following to Package.swift:
let package = Package(
name: "MySwiftPackage",
dependencies: [],
targets: [
.executableTarget(
name: "MySwiftPackage",
dependencies: [],
linkerSettings: [
.unsafeFlags(["-L lib_mac", "-lmy_rust_lib", "-import-objc-header bridging-header.h"])
]
)
]
)
This would yield the same errors.
I also tried swiftSettings instead of linkerSettings, this would give me the following error: ld: symbol(s) not found for architecture x86_64
3. I have tried the following:
file.json
{
"version": 1,
"sdk": "/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin/swift",
"toolchain-bin-dir": "/Library/Developer/Toolchains/swift-latest.xctoolchain/usr/bin",
"target": "x86_64-apple-macosx",
"dynamic-library-extension": "lib",
"extra-cc-flags": [
],
"extra-swiftc-flags": [
"-L",
"lib_mac",
"-lmy_rust_lib",
"-import-objc-header",
"bridging-header.h"
],
"extra-cpp-flags": []
}
with a Package.swift that looks like this:
let package = Package(
name: "MySwiftPackage",
dependencies: [],
targets: [
.executableTarget(
name: "MySwiftPackage",
dependencies: []
)
]
)
I then ran swift build --destination file.json, with would give me the following error:
error: no such module 'Foundation'
import Foundation
Will any of these approaches work with some changes? Or is there another approach that should work?
Thanks in advance,Jonas
P.S. I'm using macOS (12)
Related
I am writing an executable Swift package where I need to use a system library (written in C++).
AFAIK I have the package.swift, module.modulemap and umbrella header file written correctly.
When I add an import for the library in my main.swift file I get an error 'stdexcept' file not found. The error comes from an #include <stdexcept> in one of the system library's public header files.
Currently running:
Xcode v13.2.1
macOS v12.2.1 (Monterey)
I think the problem is related to Xcode's Command Line Tools but how do I fix it?
Package.swift
// swift-tools-version:5.5
import PackageDescription
let package = Package(
name: "GeodesicApp",
platforms: [.macOS(.v11)],
dependencies: [
],
targets: [
.systemLibrary(name: "geographiclib",
pkgConfig: "geographiclib",
providers: [
.brew(["geographiclib"])
]
),
.executableTarget(
name: "GeodesicApp",
dependencies: ["geographiclib"])
]
)
module.modulemap
module geographiclib {
umbrella header "geographiclib.h"
export *
link "geographiclib"
}
Umbrella header (geographiclib.h)
#include <GeographicLib/Config.h>
#include <GeographicLib/Geodesic.hpp>
main.swift
import geographiclib // error: 'stdexcept' file not found
... //
Error.
Answering my own question.
I was only able to get a working solution by creating a C wrapper package around the system library; that C wrapper package, in turn, is then wrapped with another Swift wrapper to expose 'Swifty-style' code - I was not able to get a single package that included all the required parts.
My working solution is as follows...
Package: CGeographicLib
Folder structure for the the system library's C wrapper is:
.
├── Package.swift
├── README.md
└── Sources
├── CGeographicLib
│ ├── CGeodesic.cpp
│ └── include
│ └── CGeodesic.h
└── geographiclib
├── geographiclib.h
└── module.modulemap
Updated Package.swift:
import PackageDescription
let package = Package(
name: "CGeographicLib",
platforms: [.macOS(.v11)],
products: [
.library(name: "CGeographicLib", targets: ["CGeographicLib"])
],
targets: [
.systemLibrary(name: "geographiclib",
pkgConfig: "geographiclib",
providers: [
.brew(["geographiclib"])
]),
.target(name: "CGeographicLib", dependencies: ["geographiclib"])
],
cxxLanguageStandard: .cxx20
)
I added platforms: [.macOS(.v11)] as the latest version of the GeographicLib system library only supports macOS v11 or later.
The system library that I am using has some C++11 extensions, I added the language standard .cxx20, but this could equally be .cxx11 too and it should still work for the system library I am using.
Updated module.modulemap:
module geographiclib [system] {
umbrella header "geographiclib.h"
link "geographiclib"
export *
}
Umbrella header, geographiclib.h is unchanged.
For the new C wrapper elements:
CGeodesic.h:
#ifdef __cplusplus
extern "C" {
#endif
double geoLibInverse(double lat1, double lon1, double lat2, double lon2);
#ifdef __cplusplus
}
#endif
CGeodesic.cpp:
#include "include/CGeodesic.h"
#include "../../geographiclib/geographiclib.h"
double geoLibInverse(double lat1, double lon1, double lat2, double lon2) {
using namespace std;
using namespace GeographicLib;
Geodesic geod(Constants::WGS84_a(), Constants::WGS84_f());
double s12;
geod.Inverse(lat1, lon1, lat2, lon2, s12);
return s12;
}
Package: SwiftyGeographicLib
Folder structure for the Swift package that uses the C wrapper package is:
.
├── Package.swift
├── README.md
├── Sources
│ └── SwiftyGeographicLib
│ └── Geodesic.swift
└── Tests
└── SwiftyGeographicLibTests
└── SwiftyGeographicLibTests.swift
Package.swift:
import PackageDescription
let package = Package(
name: "SwiftyGeographicLib",
platforms: [.macOS(.v11)],
products: [
.library(
name: "SwiftyGeographicLib",
targets: ["SwiftyGeographicLib"]),
],
dependencies: [
.package(name: "CGeographicLib",
url: "/Users/kieran/codeProjects/z.TestProjects/SPM/CGeographicLib",
branch: "master")
],
targets: [
.target(
name: "SwiftyGeographicLib",
dependencies: ["CGeographicLib"]),
.testTarget(
name: "SwiftyGeographicLibTests",
dependencies: ["SwiftyGeographicLib"]),
]
)
The package dependency in this example is pointing to a local package - I could equally have uploaded and created a version tag on GitHub.
Geodesic.swift:
import Foundation
import CGeographicLib
public func geodesicInverse(lat1: Double, lon1: Double, lat2: Double, lon2: Double) -> Double {
return geoLibInverse(lat1, lon1, lat2, lon2)
}
I'm working on a Typescript/nodeJS personal project. I want to create a connection to my postgres database using typeOrm but I ran into this issue:
here is the full error:
$ ts-node src/index.ts
Version 9 of Highlight.js has reached EOL and is no longer supported. Please upgrade to version 10.
Server listening at http://localhost:3002
(node:36885) UnhandledPromiseRejectionWarning: Error: No connection options were found in any orm configuration files.
at connexion_1.createConnection.error (/home/maxime/Dev/JeuxDuPlacard/packages/server/src/index.ts:7:36)
at typeorm_1.getConnectionOptions.then.catch.error (/home/maxime/Dev/JeuxDuPlacard/packages/server/src/technical/typeorm/connexion.ts:17:5)
at process._tickCallback (internal/process/next_tick.js:68:7)
at Function.Module.runMain (internal/modules/cjs/loader.js:834:11)
at Object.<anonymous> (/home/maxime/Dev/JeuxDuPlacard/packages/server/node_modules/ts-node/src/_bin.ts:182:12)
at Module._compile (internal/modules/cjs/loader.js:778:30)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:789:10)
at Module.load (internal/modules/cjs/loader.js:653:32)
at tryModuleLoad (internal/modules/cjs/loader.js:593:12)
at Function.Module._load (internal/modules/cjs/loader.js:585:3)
(node:36885) UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). (rejection id: 1)
(node:36885) [DEP0018] DeprecationWarning: Unhandled promise rejections are deprecated. In the future, promise rejections that are not handled will terminate the Node.js process with a non-zero exit code
my project structure
.
├── docker
│ ├── database.env
│ └── docker-compose.yml
├── ormconfig.ts
├── package.json
├── package-lock.json
├── src
│ ├── app.ts
│ ├── business
│ ├── index.ts
│ └── technical
│ ├── controller
│ ├── typeorm
│ │ ├── connexion.ts
│ │ └── repository
│ ├── user
│ └── validation
├── tsconfig.json
├── yarn-error.log
└── yarn.lock
./package.json
{
"name": "server",
"version": "1.0.0",
"main": "index.js",
"license": "MIT",
"type": "commonjs",
"workspaces": [
"packages/*"
],
"private": true,
"scripts": {
"dev": "tsc --watch",
"test": "echo testing server",
"start": "ts-node src/index.ts"
},
"dependencies": {
"#types/jsonwebtoken": "^8.5.0",
"bcrypt": "^5.0.0",
"body-parser": "^1.19.0",
"express": "^4.17.1",
"jsonwebtoken": "^8.5.1",
"pg": "^8.4.0",
"reflect-metadata": "^0.1.10",
"typeorm": "0.2.29",
"validate.js": "^0.13.1"
},
"devDependencies": {
"#types/bcrypt": "^3.0.0",
"#types/express": "^4.17.9",
"#types/node": "^14.14.8",
"ts-node": "3.3.0",
"ts-node-dev": "^1.0.0",
"typescript": "^4.0.5"
}
}
src/index.ts
import "reflect-metadata";
import { createConnection } from "./technical/typeorm/connexion";
import app from './app';
const port = 3002;
createConnection( error => { throw new Error(error.message) });
app.listen(port, () => console.log(`Server listening at http://localhost:${port}`))
src/technical/typeorm/connection.ts
import { PostgresConnectionOptions } from 'typeorm/driver/postgres/PostgresConnectionOptions';
import { getConnectionOptions, createConnection as TypeOrmCreateConnexion, Connection } from 'typeorm';
export async function createConnection(handleError: (error: Error) => unknown): Promise<Connection>{
return getConnectionOptions()
.then(connectionOptions => {
console.log(connectionOptions)
return TypeOrmCreateConnexion({
...(connectionOptions as PostgresConnectionOptions),
poolErrorHandler: handleError,
extra: {
max: 1
},
})
})
.catch(error => {
handleError(error);
throw error;
})
}
ormConfig.ts
import {ConnectionOptions} from "typeorm";
import path from "path";
const isCompiled = path.extname(__filename).includes('js');
const fileExtension = isCompiled ? "js" : "ts";
export default {
type: "postgres",
host: process.env.DB_HOST || "localhost",
port: Number(process.env.DB_PORT) || 5432,
username: process.env.DB_USERNAME || "test",
password: process.env.DB_PASSWORD || "test",
database: process.env.DB_NAME || "test",
synchronize: true,
logging: false,
entities: [
`src/business/**/*.entity.${fileExtension}`
],
migrations: [
`src/migration/**/*.${fileExtension}`
],
subscribers: [
`src/subscriber/**/*.${fileExtension}`
]
} as ConnectionOptions;
Apparently, typeOrm cannot find the ormConfig.ts file. This project is part of a larger monorepo which also contains the front-end connected with workspaces and lerna (I can provide more information if needed)
Any help coming from someone who can help me to find the solution about why typeORM can't find this ormConfig file will be greatly appreciated.
If you would like to use TypeORM configuration file from the root of the project, then it should be one of the next formats: .js, .json, .xml, .env, .yml, .xml (doc) (also suggest to use ormconfig without capital C).
I am trying to use resources inside my Package.swift file:
// swift-tools-version:5.3
// The swift-tools-version declares the minimum version of Swift required to build this package.
import PackageDescription
let package = Package(
name: "MyPackage",
products: [
.library(
name: "MyPackage",
targets: ["MyPackage"])
],
targets: [
.target(
name: "MyPackage",
resources: [
.process("Resources/one.xml"),
.process("Resources/two.json"),
.process("Resources/three.json"),
]
)
.testTarget(
name: "MyPackageTests",
dependencies: ["MyPackage"]
)
]
)
When I import and compile the package in another project, I am getting lots of errors, such as:
Cannot infer contextual base in reference to member 'target'
or:
Reference to member 'process' cannot be resolved without a contextual type
The files are located in my package project in Sources -> MyPackage -> Resources
I also tried .copy("Resources/one.xml"), etc
What am I missing?
You missed a , after the target close parentheses:
.target(
name: "BioSwift",
resources: [
.process("Resources/unimod.xml"),
.process("Resources/aminoacids.json"),
.process("Resources/elements.json"),
.process("Resources/enzymes.json"),
.process("Resources/functionalgroups.json"),
.process("Resources/hydropathy.json")
]
), // Here is the missed `,`
Also, you don't need to add files one by one! Instead, you can add a directory:
.process("Resources")
I'm trying to use Diesel to query a MySQL database and display the results with a Handlebars template with Rocket.
I have this in models.rs
#[derive(Queryable, Serialize)]
pub struct Post {
pub id: i32,
pub title: String,
pub text: String,
pub published: bool,
}
cargo run outputs this:
--> src/main.rs:69:5
|
69 | Template::render("index", &results)
| ^^^^^^^^^^^^^^^^ the trait `serde::ser::Serialize` is not implemented for `tasty::models::Post`
|
= note: required because of the requirements on the impl of `serde::ser::Serialize` for `std::vec::Vec<tasty::models::Post>`
= note: required by `rocket_contrib::Template::render`
In my Cargo.toml, I have this:
[dependencies]
chrono = "0.3.0"
rocket = "0.2.8"
rocket_codegen = "0.2.8"
serde = "1.0.8"
serde_derive = "1.0.8"
serde_json = "1.0.2"
mysql = "11.1.2"
diesel = { version = "0.13.0", features = ["mysql","chrono"] }
diesel_codegen = { version = "0.13.0", features = ["mysql"] }
dotenv = "0.10.0"
[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["handlebars_templates"]
I have read that Diesel does not support Serialize at the moment, but I am not sure.
The general problem is that the code has multiple versions of the crate, each providing a different version of the traits. The fact that Rust allows this is a good thing, but the error messages around it are confusing.
Your crate implements Serialize from version A but the library is using version B in a public interface. These traits are not compatible, so when you pass your type implementing Serialize#A to the function requiring Serialize#B, the compiler stops you.
While your example is about different traits, it's also possible for this to occur for types which have been re-exported from a crate.
cargo tree, available starting in Rust 1.44 is highly useful to verify this is your problem. It shows all of your dependencies and their versions. It even has a -d flag to show duplicate dependencies! That mode isn't shown here, but is highly useful.
The general solution is to manually restrict your version of Serde in your Cargo.toml to match the rest of the dependencies:
serde = "0.9"
serde_derive = "0.9"
serde_json = "0.9"
This may not always be possible, in which case you may need to hound the crate owners to upgrade their dependencies.
Worked examples
Rocket
[dependencies]
chrono = "0.3.0"
rocket = "0.2.8"
rocket_codegen = "0.2.8"
serde = "1.0.8"
serde_derive = "1.0.8"
serde_json = "1.0.2"
mysql = "11.1.2"
diesel = { version = "0.13.0", features = ["mysql","chrono"] }
diesel_codegen = { version = "0.13.0", features = ["mysql"] }
dotenv = "0.10.0"
[dependencies.rocket_contrib]
version = "*"
default-features = false
features = ["handlebars_templates"]
rocket_contrib 0.2.8 depends on Serde 0.9, but you have pulled in Serde 1.0. This abridged snippet from cargo tree shows the problem:
reproduction v0.1.0 (file:///private/tmp/reproduction)
├── rocket_contrib v0.2.8
│ ├── handlebars v0.25.3
│ │ └── serde_json v0.9.10
│ │ └── serde v0.9.15
│ ├── serde v0.9.15 (*)
│ └── serde_json v0.9.10 (*)
├── serde v1.0.8 (*)
├── serde_derive v1.0.8
│ ├── serde_derive_internals v0.15.1
└── serde_json v1.0.2 (*)
The upcoming version 0.3 of Rocket should allow using Serde 1.0.
Iron / Bson / MongoDB
[dependencies]
bodyparser = "0.5"
bson = "0.8"
iron = "0.5"
jwt = "0.4"
mongodb = "0.3"
router = "0.5"
rust-crypto = "0.2"
serde = "1.0"
serde_derive = "1.0"
serde_json = "1.0"
time = "0.1"
bodyparser 0.5 depends on Serde 0.8, MongoDB has pulled in 0.9, but the crate and BSON have pulled in Serde 1.0. This abridged snippet from cargo tree shows the problem:
reproduction v0.1.0 (file:///private/tmp/reproduction)
├── bodyparser v0.5.0
│ ├── serde v0.8.23
│ └── serde_json v0.8.6
│ └── serde v0.8.23 (*)
├── bson v0.8.0
│ ├── serde v1.0.8
│ ├── serde_json v1.0.2
│ │ └── serde v1.0.8 (*)
├── mongodb v0.3.0
│ ├── textnonce v0.6.0
│ │ ├── serde v0.9.15
│ │ └── serde_derive v0.9.15
├── serde v1.0.8 (*)
├── serde_derive v1.0.8
├── serde_json v1.0.2 (*)
Bodyparser 0.7.0 should support Serde 1.0. The state of textnonce is less clear, but that dependency might be a private one, so it might not matter in this case.
Diesel / Chrono
chrono = "0.4.0"
diesel = { version = "0.13.0", features = [ "chrono", "sqlite" ] }
diesel_codegen = { version = "0.13.0", features = [ "sqlite" ] }
dotenv = "0.9.0"
The current version of Chrono is 0.4.0, but Diesel only knows how to serialize Chrono 0.3.0.
reproduction v0.1.0 (file:///private/tmp/reproduction)
├── chrono v0.4.0
├── diesel v0.13.0
│ ├── chrono v0.3.0
blowfish / block-cipher-trait
[dependencies]
blowfish = "0.2.1"
block-cipher-trait = "0.3.0"
reproduction v0.1.0 (file:///private/tmp/reproduction)
├── block-cipher-trait v0.3.0
│── blowfish v0.2.1
├── block-cipher-trait v0.2.0
conrod / piston2d-graphics
[dependencies]
piston_window = "0.74.0"
conrod = { version = "0.56.0", features = ["piston"] }
repro v0.1.0 (file:///private/tmp/repro)
├── conrod v0.56.0
│ ├── piston2d-graphics v0.23.0
└── piston_window v0.74.0
├── piston2d-graphics v0.24.0 (*)
actix / futures
[dependencies]
actix-web = "0.6.10"
futures = "0.2.1"
repro v0.1.0 (file:///private/tmp/repro)
├── actix-web v0.6.12
│ ├── actix v0.5.8
│ │ ├── futures v0.1.21
└── futures v0.2.1
A bright future?
RFC 1977 proposes to introduce the notion of public and private dependencies to Cargo. If you use a crate that in turn publicly exposes another crate's types, Cargo would ensure that you use a single unified version for the crate with the common types.
I have the following shell script which creates a Debian base aci container for rkt / appC:
#!/bin/sh
set -e
# $ zcat debian.aci | tree | head
# $ rkt run debian.aci --insecure-options=image
export MY_CHROOT=/var/lib/container/aci/debian
mkdir -p $MY_CHROOT
debootstrap --verbose --arch=amd64 --include=iputils-ping,iproute --variant=minbase stable $MY_CHROOT/rootfs http://httpredir.debian.org/debian
cat > $MY_CHROOT/manifest <<EOF
{
"acKind": "ImageManifest",
"acVersion": "0.8.9",
"name": "debian",
"labels": [
{"name": "arch", "value": "amd64"},
{"name": "os", "value": "linux"},
{"name": "version", "value": "1.0.0"}
],
"app": {
"exec": [
"/bin/sh",
"echo",
"Hello, World from $MY_ENV_VAR!"
],
"user": "0",
"group": "0",
"environment": [
{
"name": "MY_ENV_VAR",
"value": "$(whoami)"
}
],
},
"annotations": {
"authors": "Istvan Lantos <email#addess.com>"
}
}
EOF
# use gpg to create a sig, but we'll skip that for now
tar cvvf - $MY_CHROOT/manifest $MY_CHROOT/rootfs | gzip -c > $MY_CHROOT/debian.aci
To verify that manifest file is present:
root#debian:/var/lib/container/aci/debian# zcat debian.aci | tree | head
.
├── debian.aci
├── manifest
└── rootfs
├── bin
│ ├── bash
│ ├── cat
│ ├── chacl
│ ├── chgrp
│ ├── chmod
When I try to run this container with $ rkt run debian.aci --insecure-options=image command, I got the following error:
run: missing manifest
I followed these guides for file structure:
https://github.com/appc/spec
https://github.com/appc/spec/blob/master/spec/aci.md#image-layout
https://github.com/appc/spec/blob/master/examples/image.json
Why not working?
Thank You for your help!
Actually, the error is caused by tar which includes absolute paths in the archive.
So solution is to cd in the directory and not use absolute paths prefixed by $MY_CHROOT.
Source: https://unix.stackexchange.com/a/59246/120771