name mode size
..
A 040000
B 040000
C 040000
README.md 100644 9.37kB
README.md
> Check out the [terminal movie](http://www.mulle-kybernetik.com/weblog/statics/demo-tutorial.html), instead of typing all the stuff here yourself. # "A B C" Tutorial This directory contains a simple test with 3 folder A B C, each containing a minimal Objective-C project. C depends on B, which depends on A. A depends on a system library "Foundation", which is a given. A.h ```objectivec #import <Foundation/Foundation.h> @interface A : NSObject @end ``` B imports A, but expects the header to reside in a subdirectory A B.h ```objectivec #import <A/A.h> @interface B : A @end ``` C is quite like B. C.h ```objectivec #import <B/B.h> @interface C : B @end ``` Initially none of the folders contain a `.bootstrap` folder. ## Using xcodebuild ### First problem: the header isn't found Try to build B with `xcodebuild`. It will not work, because the header `<A/A.h>` will not be found. The first step is to initalize A for **mulle-bootstrap**. You use ```console $ mulle-bootstrap init ``` At that point a `.bootstrap` will be created with some default content. Take the option to edit **gits** and you should be in an editor seeing: ```shell # add projects that should be cloned with git in order # of their inter-dependencies # # some possible types of repository specifications: # http://www.mulle-kybernetik.com/repositories/MulleScion # git@github.com:mulle-nat/MulleScion.git # ../MulleScion # /Volumes/Source/srcM/MulleScion # ``` Lines starting with a '#' are comments, these are just useless fluff in the long run, so delete them all, and add a line containing 'A'. The file now looks like this. ``` $ cat .bootstrap/gits A ``` Alright, ready to bootstrap. First lets see what **mulle-bootstrap** will do using the `-n`option ```console $ mulle-bootstrap -n Dry run is active. mkdir -p .repos There is a ../A folder in the parent directory of this project. Use it ? (y/N) ``` **A** will be found in the parent directory, and you have the option to use it, which you should do. ```console y ../A is not a git repository (yet ?) So symlinking is the only way to go. ln -s -f ../../A .repos/A [ -e .repos/A ] Dry run is active. No repos fetched, nothing to do. ``` It can not preview the build stage, because there are no repositories really setup yet. The conservative choice now is to do it in two steps. **mulle-bootstrap fetch** and then **mulle-bootstrap build**. **mulle-bootstrap** alone combined both steps into one. Lets go with **mulle-bootstrap fetch** first, so we can examine the build processs afterwards. It will be just like above, but the symlink should be in place now. ```console $ mulle-bootstrap -n build Dry run is active. mkdir -p dependencies/usr/local/include ln -s usr/local/include dependencies/include Do a xcodebuild Debug of A for SDK Default ... "xcodebuild" "install" -project "./A.xcodeproj" -configuration "Debug" ARCHS='${ARCHS_STANDARD_32_64_BIT}' DEPLOYMENT_LOCATION=YES DSTROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/tmp' INSTALL_PATH='/lib/Debug' SYMROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/build/.repos/Debug/A/' OBJROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/build/.repos/Debug/A/obj' ONLY_ACTIVE_ARCH=NO SKIP_INSTALL=NO HEADER_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include' LIBRARY_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib/Debug /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib /usr/local/lib' FRAMEWORK_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib/Debug /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib /usr/local/lib /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/Frameworks/Debug /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/Frameworks' Collecting and dispensing "A" "Debug" products Do a xcodebuild Release of A for SDK Default ... "xcodebuild" "install" -project "./A.xcodeproj" -configuration "Release" ARCHS='${ARCHS_STANDARD_32_64_BIT}' DEPLOYMENT_LOCATION=YES DSTROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/tmp' INSTALL_PATH='/lib/Release' SYMROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/build/.repos/Release/A/' OBJROOT='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/build/.repos/Release/A/obj' ONLY_ACTIVE_ARCH=NO SKIP_INSTALL=NO HEADER_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/include' LIBRARY_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib/Release /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib /usr/local/lib' FRAMEWORK_SEARCH_PATHS='/Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/include /usr/local/include /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib/Release /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/lib /usr/local/lib /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/Frameworks/Release /Volumes/Source/srcM/mulle-bootstrap/tutorial/B/dependencies/Frameworks' Collecting and dispensing "A" "Release" products ``` As the saying goes "Probieren geht ├╝ber Studieren", so lets do it for real, and use **mulle-bootstrap** build (or just **mulle-bootstrap**). This creates a lot of output now shown here. In the end we wind up with the "dependencies" folder, which should contain the following files (`ls -GFR dependencies`): ~~~ include@ dependencies/lib/Debug/libA.a dependencies/lib/Release/libA.a dependencies/usr/local/include/A.h ~~~ **include@** is a symlink to `/usr/local/include`, that will always be there. There is a library **libA** for each configuraration. The include file is in `dependencies/usr/local/include`, which is not where we need it. #### Tweaking the output We can instruct **mulle-bootstrap** to place the headers somewhere else. This is done on a per-repository basis in `.bootstrap/settings`. Since it's an xcode project, it's more foolproof to use "xcode_public_headers": ```console $ mkdir -p .bootstrap/settings/A $ echo "/usr/local/include/A" > .bootstrap/settings/A/xcode_public_headers ``` Now build it again with **mulle-bootstrap**, the header should appear as `dependencies/usr/local/include/A/A.h`, if not you may have made an exciting mistake (see "Figuring out what went wrong"). Ok, the proof is in the pudding. Let's build B again with **xcodebuild**. This will fail, because it doesn't know yet, to look in "dependecies/include" at all. #### Finally we have to tell xcodebuild where the dependencies are ```console $ mulle-bootstrap xcode add Settings will be added to B.xcodeproj. In the long term it may be more useful to copy/paste the following lines into a local .xcconfig file, that is inherited by all configurations. ----------------------------------------------------------- // Common.xcconfig: DEPENDENCIES_DIR=$(PROJECT_DIR)/dependencies HEADER_SEARCH_PATHS=$(DEPENDENCIES_DIR)/include /usr/local/include $(inherited) LIBRARY_SEARCH_PATHS=$(DEPENDENCIES_DIR)/lib/$(LIBRARY_CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) $(DEPENDENCIES_DIR)/lib/$(LIBRARY_CONFIGURATION) $(DEPENDENCIES_DIR)/lib/Release$(EFFECTIVE_PLATFORM_NAME) $(DEPENDENCIES_DIR)/lib/Release $(DEPENDENCIES_DIR)/lib /usr/local/lib $(inherited) FRAMEWORK_SEARCH_PATHS=$(DEPENDENCIES_DIR)/Frameworks/$(LIBRARY_CONFIGURATION)$(EFFECTIVE_PLATFORM_NAME) $(DEPENDENCIES_DIR)/Frameworks/$(LIBRARY_CONFIGURATION) $(DEPENDENCIES_DIR)/Frameworks/Release$(EFFECTIVE_PLATFORM_NAME) $(DEPENDENCIES_DIR)/Frameworks/Release $(DEPENDENCIES_DIR)/Frameworks $(inherited) // Debug.xcconfig: #include "Common.xcconfig" LIBRARY_CONFIGURATION=Debug // Release.xcconfig: #include "Common.xcconfig" LIBRARY_CONFIGURATION=Release ----------------------------------------------------------- Add "dependencies/lib" and friends to search paths of B.xcodeproj ? (y/N) ``` where you should say YES. Now it will build. ## Inheriting our work in C So go to folder C, and do the usual setup as ```console mulle-bootstrap init echo "B" > .bootstrap/gits mkdir -p .bootstrap/settings/B echo "/usr/local/include/B" > .bootstrap/settings/B/xcode_public_headers mulle-bootstrap ``` This will now use the dependency information from B, to automatically also build A and get the header of A into the right place. ## Using cmake Then try it again with cmake. Here we set up **mulle-bootstrap** to fetch cmake if not present and to use cmake as the only build tool: ```console cd C mulle-bootstrap clean dist # throw away results from "Using xcodebuild" echo "cmake" >> .bootstrap/brews mkdir -p .bootstrap/settings echo "cmake" >> .bootstrap/settings/build_preferences mulle-bootstrap ``` > This is actually cheaing a little, because the CMakeLists.txt files already habe 'include/[A|B]' set. But you could set dispense_public_headers like you can set xcode_public_headers.