Swift Package Manager - binaryTarget with .zip file fails to validate - swift-package-manager

I tried different approaches to add a binaryTarget to a Swift package - 2 of them worked out fine (Target1 and Target2 in the example), but third approach (Target3) that should also work according to documentation does not validate: unsupported extension for binary target 'Target3'; valid extensions are: xcframework
For not bloating the repo too much with every binary release I would prefer the zip approach here... - Anyone got it working with a binaryTarget and a .zip file in path: added to the Package repository, or any hints what I'm doing wrong here?
(Xcode 12.4, t3.zip containing only the .xcframework at root level)
// 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: "StackoverflowExamplePackage",
platforms: [
.iOS(.v9)
],
products: [
.library(
name: "Lib1",
targets: ["Target1"]),
.library(
name: "Lib2",
targets: ["Target2", "Target3"]),
],
dependencies: [
// .package(url: /* package url */, from: "1.0.0"),
],
targets: [
.binaryTarget(
name: "Target1",
url: "https://myurl.example.com/t1-xcframework.zip",
checksum: "777ddd6381e2201b7eb778b72f373f77e1190fd9dc9503f703e37c86d3b89674"
),
.binaryTarget(name: "Target2", path: "./Binaries/t2.xcframework"),
.binaryTarget(name: "Target3", path: "./Binaries/t3.zip"),
]
)

Zip archive support for local binary targets in SPM was merged last year in October and has been finally released along with Xcode 13.3.

Related

add sdk c++ headers into swift package manager project

I have a c++ project that i want to add to a swift package manager project
the c++ project references headers such as #include <string> this header resides in
iossdk/usr/include/c++/v1
how do i get the swift package manager to include those headers ?
let package = Package(
name: "LibProject",
platforms: [.iOS(.v13)],
products: [
.library(
name: "LibProject",
targets: ["LibModule1", "LibModule2Framework"]),
],
dependencies: [
],
targets: [
.target(
name: "LibModule1",
path: "Sources/LibModule1"),
.target(
name: "LibModule2Framework",
path: "Sources/LibModule2Framework",
publicHeadersPath: ".",
cxxSettings: [
.headerSearchPath("usr/include/c++/v1"),
]
),
.testTarget(
name: "LibModuleTests",
dependencies: ["LibModuleTests"]),
],
cLanguageStandard: .c17,
cxxLanguageStandard: .gnucxx17
)```

Swift Package Manager: commit in project's sub-dependency doesn't appear in package code

I have a project which uses a dependency (Lib), which contains a sub-dependency (Utilities). I have just updated this sub-dependency, adding some code, but I can't see it from my project.
Here is the dependency declared in my project:
The Package in Lib, with the dependency to Utilities:
// swift-tools-version: 5.6
import PackageDescription
let package = Package(
name: "Lib",
defaultLocalization: "en",
platforms: [
.iOS("12.1")
],
products: [
.library(name: "Lib",
targets: ["Lib"])
],
dependencies: [
.package(url: "git#bitbucket.org:__UTILITIES__.git", branch: "development")
],
targets: [
.target(name: "Lib",
dependencies: [
.product(name: "Utilities",
package: "__UTILITIES__")
],
path: "code"
]
)
__UTILITIES__ is the utilities repo
I have committed and pushed the new code in Utilities's repo, on development branch. However, whatever I try (either resetting package caches, or updating to latest package versions), I never actually get my latest code from my project.
Am I missing something?
Thank you for your help

Not able to execute lifecycle operation using script plugin

I'm trying to learn how to use script plugin. I'm following script plugin docs here but not able to make it work.
I've tried to use the plugin in two ways. The first, when cloudify.interface.lifecycle.start operation is mapped directly to a script:
tosca_definitions_version: cloudify_dsl_1_3
imports:
- 'http://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml'
node_templates:
Import_Project:
type: cloudify.nodes.WebServer
capabilities:
scalable:
properties:
default_instances: 1
interfaces:
cloudify.interfaces.lifecycle:
start:
implementation: scripts/create_project.sh
inputs: {}
The second with a direct mapping:
tosca_definitions_version: cloudify_dsl_1_3
imports:
- 'http://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml'
node_templates:
Import_Project:
type: cloudify.nodes.WebServer
capabilities:
scalable:
properties:
default_instances: 1
interfaces:
cloudify.interfaces.lifecycle:
start:
implementation: script.script_runner.tasks.run
inputs:
script_path: scripts/create_project.sh
I've created a directory named scripts and placed the below create_project.sh script in this directory:
#! /bin/bash -e
ctx logger info "Hello to this world"
hostname
I'm getting errors while validating the blueprint.
Error when operation is mapped directly to a script:
[2019-04-13 13:29:40.594] [DEBUG] DslParserExecClient - got output from dsl parser Could not extract plugin from operation mapping 'scripts/create_project.sh', which is declared for operation 'start'. In interface 'cloudify.interfaces.lifecycle' in node 'Import_Project' of type 'cloudify.nodes.WebServer'
in: /opt/cloudify-composer/backend/dev/workspace/2/tmp-27O0e1t813N6as
in line: 3, column: 2
path: node_templates.Import_Project
value: {'interfaces': {'cloudify.interfaces.lifecycle': {'start': {'implementation': 'scripts/create_project.sh', 'inputs': {}}}}, 'type': 'cloudify.nodes.WebServer', 'capabilities': {'scalable': {'properties': {'default_instances': 1}}}}
Error when using a direct mapping:
[2019-04-13 13:25:21.015] [DEBUG] DslParserExecClient - got output from dsl parser node 'Import_Project' has no relationship which makes it contained within a host and it has a plugin 'script' with 'host_agent' as an executor. These types of plugins must be installed on a host
in: /opt/cloudify-composer/backend/dev/workspace/2/tmp-279QCz2CV3Y81L
in line: 2, column: 0
path: node_templates
value: {'Import_Project': {'interfaces': {'cloudify.interfaces.lifecycle': {'start': {'implementation': 'script.script_runner.tasks.run', 'inputs': {'script_path': 'scripts/create_project.sh'}}}}, 'type': 'cloudify.nodes.WebServer', 'capabilities': {'scalable': {'properties': {'default_instances': 1}}}}}
What is missing to make this work?
I also found the Cloudify Script Plugin examples from their documentation do not work: https://docs.cloudify.co/4.6/working_with/official_plugins/configuration/script/
However, I found I can make the examples work by adding an executor line in parallel with the implementation line to override the host_agent executor as follows:
tosca_definitions_version: cloudify_dsl_1_3
imports:
- 'http://www.getcloudify.org/spec/cloudify/4.5.5/types.yaml'
node_templates:
Import_Project:
type: cloudify.nodes.WebServer
capabilities:
scalable:
properties:
default_instances: 1
interfaces:
cloudify.interfaces.lifecycle:
start:
implementation: scripts/create_project.sh
executor: central_deployment_agent
inputs: {}

QBS: Explicitly setting qbs.profiles inside Products causing build to fail

My use-case is this:
I have a static library which I want to be available for some profiles (e.g. "gcc", "arm-gcc", "mips-gcc").
I also have an application which links to this library, but this applications should only build using a specific profile (e.g. "arm-gcc").
For this I am modifying the app-and-lib QBS example.
The lib.qbs file:
import qbs 1.0
Product {
qbs.profiles: ["gcc", "arm-gcc", "mips-gcc"] //I added only this line
type: "staticlibrary"
name: "mylib"
files: [
"lib.cpp",
"lib.h",
]
Depends { name: 'cpp' }
cpp.defines: ['CRUCIAL_DEFINE']
Export {
Depends { name: "cpp" }
cpp.includePaths: [product.sourceDirectory]
}
}
The app.qbs file:
import qbs 1.0
Product {
qbs.profiles: ["arm-gcc"] //I added only this line
type: "application"
consoleApplication: true
files : [ "main.cpp" ]
Depends { name: "cpp" }
Depends { name: "mylib" }
}
The app build fails. Qbs wrongly tries to link to the "gcc" version of the library instead of the "arm-gcc" version, as you can see in the log:
Build graph does not yet exist for configuration 'default'. Starting from scratch.
Resolving project for configuration default
Setting up build graph for configuration default
Building for configuration default
compiling lib.cpp [mylib {"profile":"gcc"}]
compiling lib.cpp [mylib {"profile":"arm-gcc"}]
compiling lib.cpp [mylib {"profile":"mips-gcc"}]
compiling main.cpp [app]
creating libmylib.a [mylib {"profile":"gcc"}]
creating libmylib.a [mylib {"profile":"mips-gcc"}]
creating libmylib.a [mylib {"profile":"arm-gcc"}]
linking app [app]
ERROR: /usr/bin/arm-linux-gnueabihf-g++ -o /home/user/programs/qbs/usr/local/share/qbs/examples/app-and-lib/default/app.7d104347/app /home/user/programs/qbs/usr/local/share/qbs/examples/app-and-lib/default/app.7d104347/3a52ce780950d4d9/main.cpp.o /home/user/programs/qbs/usr/local/share/qbs/examples/app-and-lib/default/mylib.eyJwcm9maWxlIjoiZ2NjIn0-.792f47ec/libmylib.a
ERROR: /home/user/programs/qbs/usr/local/share/qbs/examples/app-and-lib/default/mylib.eyJwcm9maWxlIjoiZ2NjIn0-.792f47ec/libmylib.a: error adding symbols: File format not recognized
collect2: error: ld returned 1 exit status
ERROR: Process failed with exit code 1.
The following products could not be built for configuration default:
app
The build fails only when selecting one profile in the app.qbs file, and this profile should not be the first profile in the qbs.profiles line in the lib.qbs file.
When selecting two or more profiles - the build succeeds.
My analysis:
I think this problem is related to multiplexing:
The lib.qbs contains more than one profile. This turns on multiplexing when building the library, which, in turn, adds additional 'multiplexConfigurationId' to the build-directory name (moduleloader.cpp).
The app.lib contains only one profile, so multiplexing is not turned on and the build-directory name does not get the extra string.
The problem can be solved by changing the code (moduleloader.cpp) so that multiplexing is turned even if there is only one profile i.e. with the following patch:
--- moduleloader.cpp 2018-10-24 16:17:43.633527397 +0300
+++ moduleloader.cpp.new 2018-10-24 16:18:27.541370544 +0300
## -872,7 +872,7 ##
= callWithTemporaryBaseModule<const MultiplexInfo>(dummyContext,
extractMultiplexInfoFromProduct);
- if (multiplexInfo.table.size() > 1)
+ if (multiplexInfo.table.size() > 0)
productItem->setProperty(StringConstants::multiplexedProperty(), VariantValue::trueValue());
VariantValuePtr productNameValue = VariantValue::create(productName);
## -891,7 +891,7 ##
const QString multiplexConfigurationId = multiplexInfo.toIdString(row);
const VariantValuePtr multiplexConfigurationIdValue
= VariantValue::create(multiplexConfigurationId);
- if (multiplexInfo.table.size() > 1 || aggregator) {
+ if (multiplexInfo.table.size() > 0 || aggregator) {
multiplexConfigurationIdValues.push_back(multiplexConfigurationIdValue);
item->setProperty(StringConstants::multiplexConfigurationIdProperty(),
multiplexConfigurationIdValue);
This worked for my use case. I don't know if it make sense in a broader view.
Finally, the questions:
Does it all make sense?
Is this a normal behavior?
Is this use-case simply not supported?
Is there a better solution?
Thanks in advance.
Yes, the default behavior with multiplexing is that the a non-multiplexed product depends on all variants of the dependency. In general, there is no way for a user to change that behavior, but there should be.
However, luckily for you, profiles are special:
Depends { name: "mylib"; profiles: "arm-gcc" }
This should fix your problem.

How do I set up Quixote with Karma?

Quixote looks really cool. Am having a bit of trouble getting it working with Karma. I tried emulating Bjorn's example but am getting this error:
Error: Mismatched anonymous define() module: function () {var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
In my karma.conf.js, I have:
files: [
'www/latest/tests/lib/jasmine-beforeAll.js',
'www/latest/tests/lib/sinon-1.7.3.js',
'www/latest/tests/test-main.js',
{pattern: 'www/latest/vendor/**/*.js', included: false},
{pattern: 'www/latest/app/**/*.js', included: false},
{pattern: 'www/latest/tests/lib/*.js', included: false},
{pattern: 'www/latest/tests/specs/**/*.js', included: false},
'node_modules/quixote/dist/*.js'
],
Then in my test, I have
var quixote = require("../../../../node_modules/quixote/dist/quixote.js");
(this seems redundant as having Quixote in files hash would make it globally available but wanted to follow Bjorn's example to the letter).
Here's a plugin I made, please file tickets if it doesn't work for you. https://github.com/woldie/karma-quixote
npm install --save-dev karma-quixote

Resources