Swift Package Manager and Xcode: Retaining Xcode Settings? - swift

I am developing a server in Swift and using the Swift Package Manager. And find it convenient when doing my development on my Mac OS system to generate a Xcode project to use Xcode as my IDE (i.e., From time to time, my package dependencies have to be updated. I've been using swift package generate-xcodeproj to do this. My problem comes in at this point-- I have created some settings in Xcode. E.g., I've set a DEBUG flag, and I have a .plist file that is in the Copy Files Phase. These get lost when I regenerate the Xcode project. It seems I cannot simply use swift package update because sometimes files change in the dependencies and these don't get propagated to the Xcode project.
What I'd like is a means to separately establish Xcode settings in a file outside of Xcode, that can be imported into Xcode when I do the swift package generate-xcodeproj. I have not seen a way to do this.
A related question is: When I do a swift build I'd like those same build settings to be used.
Suggestions?

I can't help with Copy Files Phase.
However I have just been toying with conditional compilation, like this:
swift package generate-xcodeproj --xcconfig-overrides Sandbox.xcconfig
Sandbox.xcconfig
FLAG_SANDBOX = -DSANDBOX
OTHER_SWIFT_FLAGS = $(FLAG_SANDBOX)
This creates an Xcode project where SANDBOXis definded.
This can be used in swift code like this
#if SANDBOX
print("sandbox")
#else
print("production")
#endif

I would use a script or a makefile to import your settings into the generated Xcode project, each time you regenerate it. You can use xcodeproj rubygem.
See an example script.
Regarding using your settings in swift build, can you give an example of such a setting? In general, a makefile can read your settings file and pass the corresponding parameters to swift build.

Based on #vadim's answer above, here's a xcodeproj rubygem solution to the first part of my question:
#!/usr/bin/ruby
# Tweak the .xcodeproj after creating with the swift package manager.
# Resources:
# https://stackoverflow.com/questions/41527782/swift-package-manager-and-xcode-retaining-xcode-settings/41612477#41612477
# https://stackoverflow.com/questions/20072937/add-run-script-build-phase-to-xcode-project-from-podspec
# https://github.com/IBM-Swift/Kitura-Build/blob/master/build/fix_xcode_project.rb
# http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj%2FProject%2FObject%2FAbstractTarget%3Anew_shell_script_build_phase
# http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/Object/AbstractTarget
# https://gist.github.com/niklasberglund/129065e2612d00c811d0
# https://github.com/CocoaPods/Xcodeproj
# https://stackoverflow.com/questions/34367048/how-do-you-automate-do-copy-files-in-build-phases-using-a-cocoapods-post-insta?rq=1
require 'xcodeproj'
path_to_project = "Server.xcodeproj"
project = Xcodeproj::Project.open(path_to_project)
# 1) Add Copy Files Phase for Server.plist to the Products directory for Server target
target = project.targets.select { |target| target.name == 'Server' }.first
puts "Add Copy Files Phase to #{target}"
phase = target.new_copy_files_build_phase()
# Contrary to the docs (see http://www.rubydoc.info/github/CocoaPods/Xcodeproj/Xcodeproj/Project/Object/PBXCopyFilesBuildPhase) I believe this is not a path, but rather a code, e.g., 16 indicates to copy the file to the Products Directory.
phase.dst_subfolder_spec = "16"
fileRef = project.new(Xcodeproj::Project::Object::PBXFileReference)
fileRef.path = 'Server.plist'
phase.add_file_reference(fileRef)
# 2) Add in script phase for testing target-- because I haven't figured out to get access to the Products directory at test-run time.
target = project.targets.select { |target| target.name == 'ServerTests' }.first
puts "Add Script Phase to #{target}"
phase = target.new_shell_script_build_phase()
phase.shell_script = "cp Server.plist /tmp"
# 3) Add in DEBUG flag
# A little overkill, but hopefully appending a DEBUG flag in the Debug configuration for each target doesn't hurt it.
project.targets.each do |target|
puts "Appending DEBUG flag to #{target}"
if target.build_settings('Debug')['OTHER_SWIFT_FLAGS'].nil?
target.build_settings('Debug')['OTHER_SWIFT_FLAGS'] = ""
end
target.build_settings('Debug')['OTHER_SWIFT_FLAGS'] << '-DDEBUG'
end
project.save()

Related

Redefinition of module 'Firebase'

I'm trying to integrate Firebase into my app, but as soon as I'm building it after I thought I finished my install I get:
Redefinition of module 'Firebase'
as well as
Could not build Objective-C module 'SwiftOverlayShims'
which I have no idea what that means but I'm assuming its a result of the first.
My podfile looks like this:
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'app' do
# Comment the next line if you don't want to use dynamic frameworks
use_frameworks!
pod 'Firebase/Auth'
# Pods for app
end
So I don't think theres anything conflicting there. I saw a solution that told me to go into my Header Search Path and see if my project had multiple Firebase directories, but I have no custom paths, so that wasn't it. Any insight?
EDIT: Here is the exact display from my errors
Uncommenting the platform line in my podfile and changing it to iOS 10.0 did get rid of the error saying "Could not build Objective-C module 'Firebase'" So we have made some progress.
Here is the path when selecting "previously defined here"
From what I can tell, it is only giving me one location. Selecting the redefinition error just gives me the relative path of module.modulemap , so I am assuming that is referring to the same thing. I am also getting multiple warnings like this
Skipping duplicate build file in Copy Files build phase: /Users/me/Library/Developer/Xcode/DerivedData/app-elgcucdextsnzqbtlznbqeulbfks/SourcePackages/artifacts/Firebase/FirebaseAnalytics.xcframework/ios-arm64_i386_x86_64-simulator/FirebaseAnalytics.framework
as well as a couple other frameworks in the ios-arm64_i386_x86_64-simulator directory, so maybe that has something to do with it.

buildroot package from local source with snapshots

I want to fork buildroot, add a custom package, add the package's source directly in-tree, and have buildroot use the in-tree source to build the custom package. I've done that, following chapter 17 of the buildroot user manual, but buildroot doesn't seem to be picking up local changes that I've made.
For example, I built the entire image, and it also built my custom application. Then I went into the source for my custom application and added an intentional syntax error -- but then I ran make again and it happily generated an image using the old version of my custom app.
How do I tell buildroot to look for local source modifications, even if it already has a cached build of the package with a matching version?
These are the new files which I have added to my buildroot fork:
buildroot/
package/
customapp/
customapp.mk
Config.in
customapp/
configure.ac
Makefile.am
README
src/
main.c
Makefile.am
(I also edited buildroot/package/Config.in so that it sources the buildroot/package/customapp/Config.in file. All the Config.in stuff is just a simple boolean to enable customapp, and they work fine, so I'll omit them from this question.)
Here are the contents of the build-related files:
buildroot/package/customapp/customapp.mk
CUSTOMAPP_VERSION = 0.1
CUSTOMAPP_SITE = customapp
CUSTOMAPP_SITE_METHOD = local
CUSTOMAPP_AUTORECONF = YES
$(eval $(autotools-package))
buildroot/customapp/configure.ac
AC_INIT([customapp], [0.1], [name#email.tld])
AM_INIT_AUTOMAKE([-Wall -Werror foreign])
AC_PROG_CC
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([
Makefile
src/Makefile
])
AC_OUTPUT
buildroot/customapp/Makefile.am
SUBDIRS = src
dist_doc_DATA = README
buildroot/customapp/src/Makefile.am
bin_PROGRAMS = customapp
customapp_SOURCES = main.c
Section 8.3 of the buildroot manual explains how to rebuild a single package. The easiest way is with [package name]-rebuild target. In your case it would be:
make customapp-rebuild
You may want to also trigger the buildroot post build actions to rebuild the target device file system images after your package re-build is complete:
make target-post-image
To rebuild a buildroot package, you have to remove the stamp files in output/build/customapp-version/.stamp*. The easiest way is to remove the whole build directory.
Buildroot relies only on the .stamp files for understanding what needs to be rebuild.

How to generate a framework from a SwiftPM-generated XCode project?

I used SwiftPM to set up an XCode project for a framework; based on
// swift-tools-version:4.0
import PackageDescription
let package = Package(
name: "MyThing",
products: [
.library(
name: "MyThing",
targets: ["MyThing"]),
],
dependencies: [
],
targets: [
.target(
name: "MyThing",
dependencies: [])
)
I ran swift package generate-xcodeproj and then pod install (based on a Podfile whose content shouldn't matter). I obtain MyThing.xcworkspace.
Now I figured that
xcodebuild -workspace MyThing.xcworkspace -scheme MyThing clean build
should create the .framework -- but it doesn't, only a binary file appears. I suspect some automatism is at work here since the source folder contains a file named main.swift, among others.
What do I have to do to get the framework built?
I need to script the whole process, to please no manual workarounds.
As of Swift 4.0 swift package generate-xcodeproj doesn't automatically generate schemes for all targets, but still makes those targets accessible from Xcode.
If creating a new scheme manually once is acceptable, you can do so and add your framework target as a scheme build target.
Otherwise, new schemes can be created programmatically with libraries like xcodeswift/xcproj, which allow you to parse a newly generated Xcode project and generate a new scheme with its XCSharedData class.
After that new framework scheme is created you can run the build with xcodebuild -workspace MyThing.xcworkspace -scheme MyThingFramework clean build.
Mixing script files and framework code in one target seems to confuse SwiftPM. Moving main.swift out of the source folder clears up things.
Scheme MyThing-Package creates all build products as specified in Package.swift, including the framework.
If you want to have the script files in the same XCode Workspace (for editing convenience), put them in their own target. You can even create an executable product (which won't create anything useful since an executable can't link to dynamic frameworks).

Why I cant import the library that in swift file after installing the the dependency in Cocoapods?

I already install this library, XLPagerTabStrip via Cocoapod. My pod file is look like this,and already hit pod install in terminal.
# Uncomment the next line to define a global platform for your project
# platform :ios, '9.0'
target 'MyProject' do
# Comment the next line if you're not using Swift and don't want to use dynamic frameworks
use_frameworks!
# Pods for MyProject
pod 'XLPagerTabStrip', '~> 8.0'
end
So everything is completed install,but when I want to import the library in Swift file,it giving an error ->> No such module 'XLPagerTabSript'.
I read a lot of question about this,which mention add the file path of the library to
Build Setting -> Search Paths -> User Header Search Paths. I also already did,but still giving the same error.
What I add in User Header Search Path is something like this:
${SRCROOT}/Users/Myname/Desktop/MyProject/Pods/XLPagerTabStrip
After adding the file path,I clean the project,build the project again,the tried to add in import XLPagerTabStrip to one of my swift file,the error still the same.
Can somebody let me know what is problem actually? Cause I beginner in Ios development,I totally no idea what I doing wrong.
I end up solve it by update my Xcode vesion and insert the file path of the library in inside
Build Setting -> Search Paths -> Framework Search Paths -> (Add the
file path of the library here)
By this I can import the library in swift file without any warning

How to add pre-build step in qmake/qtcreator?

I want the compiled application to have the commit number, source files checksums and other things to be available during the compilation.
In plain Makefiles I do like this:
prog: VERSION source.c
gcc -DVERSION=\"$(shell cat VERSION)\" source.c -o prog
VERSION: .git
git describe > VERSION
How to use something similar with qmake?
If you were to pass the version information as an included file (let's say "version.h") instead of a #define, then you could add the following to your qmake file
# Define how to create version.h
version.target = version.h
version.commands = <PUT_YOUR_COMMANDS_HERE>
version.depends = .git
QMAKE_EXTRA_TARGETS += version
PRE_TARGETDEPS += version.h
The first 3 lines tell how to make a new target object called "version" that generates "version.h". It is made by executing the commands "<PUT_YOUR_COMMANDS_HERE>". The target is dependent on ".git"
The "QMAKE_EXTRA_TARGETS" says there is a new target known as "version".
The "PRE_TARGETDEPS" indicates that "version.h" needs to exist before anything else can be done (which forces it to be made if it isn't already made).
A simpler solution even if #jwernemy as nice way to solve it:
VERSION = $$system(-git-dir=$PWD/.git <PUT_YOUR_GIT_COMMANDS_HERE>)