Open nanotech opened 7 years ago
Ok, I'm having trouble giving you a good recommendation here. I was in fact expecting the first option because in my case most of the development happens on the Haskell side, I don't expect to be calling a lot of Swift functions from Haskell.
Yes, I do think going Swift -> Haskell is generally the better option, but wanted to document some reasons why the other way could or couldn't work too.
I mean I think if you can make it work or explain the issue well, that's useful.
Sorry for the delay. Attempting to go through the tutorial and so far when I get to the build after setting up runNSApplication. I get the following:
biglambda$ stack build
CruxLibrary-0.1.0.0: build
Preprocessing executable 'Crux' for CruxLibrary-0.1.0.0...
Linking .stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Crux/Crux ...
ld: framework not found CruxLibrary
clang: error: linker command failed with exit code 1 (use -v to see invocation)
gcc' failed in phase
Linker'. (Exit code: 1)
-- While building package CruxLibrary-0.1.0.0 using: /Users/biglambda/.stack/setup-exe-cache/x86_64-osx/setup-Simple-Cabal-1.24.2.0-ghc-8.0.2 --builddir=.stack-work/dist/x86_64-osx/Cabal-1.24.2.0 build exe:Crux --ghc-options " -ddump-hi -ddump-to-file" Process exited with code: ExitFailure 1
Not sure where to place the framework. My directory structure is the same as yours I think.
I did forget to mention to build the framework at the end of the Converting the Swift App to a Framework section, so you might just need to build the framework in Xcode before stack build
ing. I've added that in now.
The framework should be symlinked to its location in the Xcode build directory from the project's build/ directory. The symlink should be created by the Run Script phase added at the end of the Converting the Swift App to a Framework section.
Here's what's in my project's build directory after a successful build:
# tree -a build
build
├── SwiftAppLibrary.framework -> /Users/nanotech/Library/Developer/Xcode/DerivedData/SwiftHaskell-cwfykomvmcuamcbfwulxhcfjpbdi/Build/Products/Debug/SwiftAppLibrary.framework
├── SwiftHaskell -> ../.stack-work/dist/x86_64-osx/Cabal-1.24.0.0/build/SwiftHaskell/SwiftHaskell
└── ghc
└── include -> /Users/nanotech/.stack/programs/x86_64-osx/ghc-8.0.1/bin/../lib/ghc-8.0.1/include
3 directories, 1 file
Sorry for this, I'm pretty new to XCode, I haven't been able to build the framework, getting some strange errors in XCode:
-- file:///Users/biglambda/Software/crux/xcode/.DS_Store: warning: Missing file: /Users/biglambda/Software/crux/xcode/.DS_Store is missing from working copy
-- PBXCp build/Crux /Users/biglambda/Library/Developer/Xcode/DerivedData/Crux-henfnnwgwlypjocyelgjcuwrmuzb/Build/Products/Debug/CruxLibrary.framework/Versions/A/Crux cd /Users/biglambda/Software/crux/xcode/Crux builtin-copy -exclude .DS_Store -exclude CVS -exclude .svn -exclude .git -exclude .hg -resolve-src-symlinks /Users/biglambda/Software/crux/xcode/Crux/build/Crux /Users/biglambda/Library/Developer/Xcode/DerivedData/Crux-henfnnwgwlypjocyelgjcuwrmuzb/Build/Products/Debug/CruxLibrary.framework/Versions/A
error: /Users/biglambda/Software/crux/xcode/Crux/build/../.stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Crux/Crux: No such file or directory
-- file:///Users/biglambda/Software/crux/xcode/.DS_Store: warning: Missing file: /Users/biglambda/Software/crux/xcode/.DS_Store is missing from working copy
A crux/xcode/.DS_Store
Finder display settings file was staged into git and then deleted from the working copy. I think running git rm crux/xcode/.DS_Store
should clear this up. For the future, add .DS_Store
to your global gitignore (at ~/.config/git/ignore
by default).
-- PBXCp build/Crux ... No such file or directory
Xcode is trying to copy the Haskell executable into the app bundle here, but it isn't built yet. You don't need to build the app bundle yet though, just the framework, so set the framework as the current target before building:
The tutorial describes the build ordering a bit later in the middle of Linking to the Executable.
That doesn't seem to solve the "PBXCp build/Crux ... No such file or directory" error.
It says in the tutorial to make SwiftAppLibrary the only target of AppDelegate.swift and MainMenu.xib. It seems greyed out for AppDelegate.swift
Can you check the Build Phases of the two targets? Target membership checkboxes can be greyed out if a Compile Sources phase is missing. For the framework, they should be
stack build; bash link-deps.sh
set -u; ln -sf "${BUILT_PRODUCTS_DIR}/${FULL_PRODUCT_NAME}" "${PROJECT_DIR}/build/"
For the app bundle,
Substitute SwiftHaskell and SwiftAppLibrary with your Haskell executable and Swift framework names respectively.
The only time Xcode should be copying from build/../.stack-work/dist/x86_64-osx/Cabal-1.24.2.0/build/Crux/Crux
is in the last Copy Files phase of the app bundle target.
Ok the library builds properly but the app still gives:
Unable to run command 'PBXCp Crux.app' - this target might include its own product. Unable to run command 'ValidateEmbeddedBinary Crux.app' - this target might include its own product. Unable to run command 'Touch Crux.app' - this target might include its own product. Unable to run command 'CodeSign Crux.app' - this target might include its own product. Unable to run command 'RegisterWithLaunchServices Crux.app' - this target might include its own product.
this target might include its own product
Is the app's Executable Copy Files phase perhaps set to copy Crux.app (the built app bundle and product of the app target) instead of build/Crux (the Haskell executable)?
Ok, seems to be building but crashes:
dyld: Library not loaded: @rpath/libswiftAppKit.dylib Referenced from: /Users/biglambda/Library/Developer/Xcode/DerivedData/Crux-henfnnwgwlypjocyelgjcuwrmuzb/Build/Products/Debug/CruxLibrary.framework/Versions/A/CruxLibrary Reason: image not found (lldb)
Here's the build phases: http://imgur.com/mcGGB8R
In the framework target's Build Settings, is Always Embed Swift Standard Libraries set to Yes?
Your build phases all look correct.
Here's the contents of the tutorial project's compiled app:
$ tree -a SwiftHaskell.app
SwiftHaskell.app
└── Contents
├── Frameworks
│ └── SwiftAppLibrary.framework
│ ├── Resources -> Versions/Current/Resources
│ ├── SwiftAppLibrary -> Versions/Current/SwiftAppLibrary
│ └── Versions
│ ├── A
│ │ ├── Frameworks
│ │ │ ├── libswiftAppKit.dylib
│ │ │ ├── libswiftCore.dylib
│ │ │ ├── libswiftCoreData.dylib
│ │ │ ├── libswiftCoreGraphics.dylib
│ │ │ ├── libswiftCoreImage.dylib
│ │ │ ├── libswiftDarwin.dylib
│ │ │ ├── libswiftDispatch.dylib
│ │ │ ├── libswiftFoundation.dylib
│ │ │ ├── libswiftIOKit.dylib
│ │ │ ├── libswiftObjectiveC.dylib
│ │ │ ├── libswiftQuartzCore.dylib
│ │ │ ├── libswiftSwiftOnoneSupport.dylib
│ │ │ └── libswiftXPC.dylib
│ │ ├── Resources
│ │ │ ├── Base.lproj
│ │ │ │ └── MainMenu.nib
│ │ │ ├── Info.plist
│ │ │ └── libswiftRemoteMirror.dylib
│ │ ├── SwiftAppLibrary
│ │ └── _CodeSignature
│ │ └── CodeResources
│ └── Current -> A
├── Info.plist
├── MacOS
│ └── SwiftHaskell
├── PkgInfo
├── Resources
└── _CodeSignature
└── CodeResources
14 directories, 23 files
Ok it was set to no. It's running now and showing the window. I'll go through the rest tonight and we can finish up the bounty. Basically all I think should happen to complete the tutorial is a little more explanation of why. Assume most haskellers have zero knowledge of Xcode or this method of linking so:
-- Each symlink you've created in your shell script should have an explanation of it's purpose. -- More explanation of why you chose the various settings in XCode. -- Links to further understanding in Apple documentation, books or elsewhere. Show us how to get this specialization. -- Include all of the information from this troubleshooting thread in the tutorial. -- Also you should submit a pull request to Daniel the cabal-macosx maintainer if you haven't already.
Great work and thanks.
Also I didn't quite use the same names as you did. When you "import SwiftHaskell" in your AppDelegate.swift, to which file are you referring? I see, it's in the module.modulemap file. Why would I get a AppDelegate.swift:20:32: Use of unresolved identifier 'square'
Great!
Setting instructions now have more explanation.
I also switched the Always Embed Swift Standard Libraries setting to be set on the app bundle target instead of the framework. It works both ways, but this way is more consistent with other Swift apps.
cabal-macosx
branches.Yes, import SwiftHaskell
is referring to the name defined in the module.modulemap
.
Use of unresolved identifier 'square'
The first warning
File 'AppDelegate.swift' is part of module 'Crux'; ignoring import
is the clue. The product/module/target that contains AppDelegate.swift
is apparently named Crux, so the import is importing the current module, which is redundant. This seems wrong, since you also have a CruxLibrary framework target that AppDelegate.swift should be in instead. Check the Target Membership of the file.
Additionally, make sure the name in module.modulemap
(the Haskell executable name) is different from CruxLibrary (the Swift framework name).
Sorry about this, I started over with a fresh project and tried to use all the exact same filenames trying very hard to follow all the details. I also tried cloning the repositorie. In the first case I can build the initial empty window but when I try adding the label that references square I get this error: (I also tried building the cloned project file and got a similar error)
/Users/biglambda/Library/Developer/Xcode/DerivedData/SwiftHaskell-gbesrmujipgqmsdlyyeowmwpsjfu/Build/Intermediates/SwiftHaskell.build/Debug/SwiftAppLibrary.build/unextended-module.modulemap:2:19: error: umbrella header 'SwiftAppLibrary.h' not found umbrella header "SwiftAppLibrary.h" ^
error: use of unresolved identifier 'square'
This appears to be from Xcode incorrectly caching some previous state of the SwiftHaskell module before it was fully configured. Performing a full clean (Product » Clean Build Folder... ⌥⇧⌘K) and rebuilding fixes this for me, and it doesn't appear again. I've only been able to reproduce this when starting the tutorial fresh through to the end.
I've added this workaround to the tutorial.
error: umbrella header 'SwiftAppLibrary.h' not found
This was occurring in the tutorial project because I had the Enable Modules setting incorrectly disabled. The default is enabled in newly created Swift projects.
I didn't notice earlier because it only fails on the first build after a (normal) clean. It would work after the first build because the header copy phase is after the compile phase, and the compile phase would use the copied header from the previous build. Enabling modules seems to either set the internal include paths correctly or also copy the header before compiling.
I wasn't able to reproduce this in a fresh project, but, see what cleaning the build folder does for this. These Stack Overflow answers have some other possibilities, although none of them should apply in a fresh project following the tutorial.
Ok, that works but it leads to a runtime error: http://imgur.com/1Z7oIbu
hello world
fatal error: unexpectedly found nil while unwrapping an Optional value
2017-02-25 21:33:30.126607 SwiftHaskell[74938:2734572] fatal error: unexpectedly found nil while unwrapping an Optional value
Current stack trace:
0 libswiftCore.dylib 0x000000010044fce0 swift_reportError + 132
1 libswiftCore.dylib 0x000000010046d090 _swift_stdlib_reportFatalError + 61
2 libswiftCore.dylib 0x00000001002630c0 specialized specialized StaticString.withUTF8Buffer ((UnsafeBufferPointer
You need to add the label in interface builder and connect it to the AppDelegate's outlet.
Add a new label to the window in MainMenu.xib for us to write the result of our Haskell function square into
Granted, the instruction is a little brief compared to the rest of the tutorial. I'll expand it.
I've added a more detailed explanation on how to add and connect the label with Interface Builder.
Cool, I'm all the way through. I sent the rest of the bounty.
Fantastic! Thanks.
The first choice to make for the direction of the tutorial is whether to let GHC or swiftc build the final executable. I chose to let Xcode and swiftc build the executable, but having GHC link to a Swift framework might be a good choice too. Reasons to embed the Haskell library include
Reasons not to:
cabal-macosx
.The Xcode project currently includes
stack build
as a build script phase, but this could be inverted by havingSetup.hs
callxcodebuild
.The tutorial currently only covers passing integers from Swift to Haskell, but I'd like to also cover passing bytestrings and functions in both directions.