I've been working thought some examples of building swift code from the command line, and I'm a little bit unclear about the precise difference between the two swiftc options: -emit-module and -emit-library.
I can see that -emit-module produces a .swiftmodule and a .swiftdoc, while -emit-library produces a .dylib, but what are the practical differences between these two? In which cases would I choose one or the other?
The -emit-library creates a dynamic library that can be linked into an executable. The -emit-module creates, as you note, the files needed to hold the definition of a module for the swift compiler and tools to use when compiling other pieces of swift code. They do not include the object code that can be linked into an executable. When you build a framework for others to use, you need to include everything. If you look at the contents of an Apple framework, you'll see a binary file with the name of the framework, which is a dynamic library without the .dylib extension, and a Modules directory, which holds the .swiftmodule and .swiftdoc.
Building on my previous response, you could use -emit-library if you need the object code for the module routines to be linked into an executable. You would use the -emit-module if you want to generate the representation of the module that can be used by the swift compiler for compiling other code, or for other compiler-related tools (linters, syntax/semantic processors, etc.). Lots of folks are looking at tooling using the .swiftmodule/.swiftdoc artifacts. The linker uses the .dylib.
So now I am running into another issue maybe you know the answer to: once I have built my executable, I run into a dyld: Library not loaded error when trying to run the executable.
And I am building the library and executable with these commands respectively:
$ cd build/lib
$ swiftc -emit-module -emit-library ../../lib/lib.swift
$ cd build/executable
$ swiftc -I../lib -L../lib -llib ../../executable/main.swift -o ./main
The complete error is this:
dyld: Library not loaded: liblib.dylib
Referenced from: path/to/build/executable/main
Reason: image not found
Abort trap: 6
So if I understand, the problem is that the executable cannot be linked with the dylib at runtime.
Interestingly, if I run the executable from the directory where liblib.dylib is located, it works perfectly.
So the question is, how do I correctly specify the path to the dynamic library for the executable to find it at runtime? I would have thought the -L argument would specify this.
It works because the dynamic linker looks in the path of the executable for the dynamic library. If it's not there, it looks through the paths that are encoded in the executable for the dynamic library lookup. If it can't find it there, it looks at the contents of DYLD_LIBRARY_PATH environment variable. If it can't find it there, it looks at standard locations like /usr/lib, /usr/local/lib. For more information, look at the man page for dyld, the dynamic linker, which is invoked as part of the "swift build" command (the "swift/swiftc" command is driver that invokes several tools based on what is being accomplished at the time).
When you use "-L ../lib", the linker puts that string "../lib" in the executable as the path for the library. Unless you are running the executable in a directory that is a peer to "lib", the line is not going to find it. I would try putting in an absolute path to the library.
You can use "otool -L hola" to get a list of the paths of the dynamic libraries that are referenced by the executable.
You can also look at the discussion on rpath in the dyld man page to look at other methods for specifying load paths.