Setup EFI Development environment on Mac OSX Sierra (10.12.X)
2017-07-10 05:55:39 +0200 - Written by Mikal Villa
Oh no! a lot of text. Well, luckly half of the post is troubleshooting. EFI development setup is easy :)
Okay, before starting this guide you should have some tools installed already.
- Mac OS X. For this guide I run version 10.12.5 (16F73)
- Xcode 8. For this guide I run version 8.3.2 (8E2002)
- Homebrew. A package manager for Mac OS X. https://brew.sh
First of all visit https://opensource.apple.com/release/developer-tools-821.html
You need to download the cctools
package. This package contains various tools to deal with Mach-O files, which is the default binary file format used by the XNU kernel. It is an equivalent to the GNU binutils package on the GNU OS. (directlink)
While you’re still at it, download the ld64
package as well. This package contains the dynamic linker ld, as well as other tools and libraries related to it. It replaces the old ld-classic from the cctools package that was not 64 bit-capable. (directlink)
You will also need some llvm headers, because of that you need to download the llvm source at http://releases.llvm.org/download.html#4.0 (directlink)
Just to not confuse with paths, set export EFIWORKSPACE=~/EfiWorkspace
and make sure it exists with mkdir $EFIWORKSPACE
Buidling ld64
First of all, I recommend that you patch the project file to avoid errors it’s a great chance you get if not. The patch is pasted below.
--- ld64.xcodeproj/project.pbxproj2 2017-05-28 18:14:26.000000000 +0200
+++ ld64.xcodeproj/project.pbxproj 2017-05-28 18:29:44.000000000 +0200
@@ -1463,19 +1463,26 @@
F933D92409291AC90083EAC8 /* Debug */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_DYNAMIC_NO_PIC = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../cctools-895/include/";
ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx.internal;
+ USER_HEADER_SEARCH_PATHS = "";
};
name = Debug;
};
F933D92509291AC90083EAC8 /* Release */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_DYNAMIC_NO_PIC = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../cctools-895/include/";
+ ONLY_ACTIVE_ARCH = YES;
SDKROOT = macosx.internal;
+ USER_HEADER_SEARCH_PATHS = "";
};
name = Release;
};
@@ -1500,9 +1507,12 @@
F9849FF810B5DE8E009E9878 /* Release-assert */ = {
isa = XCBuildConfiguration;
buildSettings = {
+ ARCHS = "$(ARCHS_STANDARD_32_64_BIT)";
GCC_DYNAMIC_NO_PIC = NO;
GCC_TREAT_WARNINGS_AS_ERRORS = NO;
+ HEADER_SEARCH_PATHS = "$(SRCROOT)/../cctools-895/include/";
SDKROOT = macosx.internal;
+ USER_HEADER_SEARCH_PATHS = "";
};
name = "Release-assert";
};
ln -sf /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk $EFIWORKSPACE/ld64-274.2/macosx.internal
# Depending on if you want a debug or release build, choose one of the following:
# Debug
xcodebuild ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -scheme libprunetrie -configuration Debug -destination 'platform=OS X,arch=x86_64' build
# Release
xcodebuild ARCHS="i386 x86_64" ONLY_ACTIVE_ARCH=NO -sdk /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk -scheme libprunetrie -configuration Release -destination 'platform=OS X,arch=x86_64' build
# Mine ended up in /Users/mikalv/Library/Developer/Xcode/DerivedData/ld64-ffssbvtdnxqygzfcarplcybwxblo/Build/Products/Debug/libprunetrie.a
# Look at the last output from the command to find yours
# Copy it to a path that cctools makefile will look for libraries in
cp /Users/mikalv/Library/Developer/Xcode/DerivedData/ld64-ffssbvtdnxqygzfcarplcybwxblo/Build/Products/Debug/libprunetrie.a /usr/local/lib/libprunetrie.a
Running cmake on llvm
Next up, we need to run cmake on llvm, but we don’t need to compile it.
mkdir $EFIWORKSPACE/build-llvm
cd $EFIWORKSPACE/build-llvm
cmake $EFIWORKSPACE/../llvm-4.0.0.src
cp include/llvm/Support/DataTypes.h $EFIWORKSPACE/../cctools-895/include/llvm/Support/
cd $EFIWORKSPACE
Buidling cctools
cp $EFIWORKSPACE/cctools-895/include/llvm-c/Disassembler.h $EFIWORKSPACE/
rm -fr $EFIWORKSPACE/cctools-895/include/llvm-c
cp -r $EFIWORKSPACE/llvm-4.0.0.src/include/llvm-c cctools-895/include/llvm-c
cd $EFIWORKSPACE/cctools-895
make
cd efitools
make
# Finally we got the mtoc binary, now copy it to a directory in your PATH
cp mtoc.NEW /usr/local/bin/mtoc
cd $EFIWORKSPACE
Installing remaining dependencies
In this guide I assume you got /usr/local/bin
in your path because of Homebrew. If not, this will not work at all.
Now we need to install, or upgrade the tools we need from Homebrew.
brew install nasm acpica qemu
You can verify all tools are installed with checking their version.
mtoc
qemu-system-x86_64 --version
nasm –v
iasl –v
EDK II
Finally we’re done with dependencies and can start with the fun part. Since using git tags is too complicated for the EDK II developers, we have to sync via commit hashes. The one I’m using is f4d3ba87bb8f5d82d3b80532ea4c83b7bbca41c0
cd $EFIWORKSPACE
git clone https://github.com/tianocore/edk2.git
cd edk2
make -C BaseTools
# Optionally use the same version as me.
git checkout f4d3ba87bb8f5d82d3b80532ea4c83b7bbca41c0
source edksetup.sh
Now you can start your own projects and play around with EFI. Enjoy :)
Troubleshooting compiler errors
If you encounte
r errors, I collected a list below of some errors that you might have gotten.
The missing llvm/Support/DataTypes.h
header file
=========== /Applications/Xcode.app/Contents/Developer/usr/bin/make all for libstuff =============
cc -std=c99 -Os -DLTO_SUPPORT -g -I../../include -Wall -D_MACH_I386_THREAD_STATUS_FPSTATE_LEGACY_FIELD_NAMES_ -D_ARCHITECTURE_I386_FPU_FPSTATE_LEGACY_FIELD_NAMES_ -c \
-I/Developer/usr/local/include \
-I/usr/local/include \
-o ./lto.o ../lto.c
cc -Os -DLTO_SUPPORT -g -I../../include -Wall -D_MACH_I386_THREAD_STATUS_FPSTATE_LEGACY_FIELD_NAMES_ -D_ARCHITECTURE_I386_FPU_FPSTATE_LEGACY_FIELD_NAMES_ -c -o ./llvm.o ../llvm.c
In file included from ../llvm.c:6:
../../include/llvm-c/Disassembler.h:18:10: fatal error: 'llvm/Support/DataTypes.h' file not found
#include "llvm/Support/DataTypes.h"
^
1 error generated.
make[2]: *** [llvm.o] Error 1
Solution is:
If you’re missing DataTypes.h
you probably forgot to run cmake on llvm
and copy the header generated. There is an DataTypes.h.cmake
in that directory, which gets generated to DataTypes.h
after running cmake.
The missing mach-o/prune_trie.h
header file
cc -Os -DLTO_SUPPORT -DTRIE_SUPPORT -g -Wall -I. -I./../include -I. -I/usr/local/include -c \
-o ./nmedit.o ./strip.c -DNMEDIT
./strip.c:50:10: fatal error: 'mach-o/prune_trie.h' file not found
#include <mach-o/prune_trie.h>
^
1 error generated.
make[1]: *** [nmedit.o] Error 1
make: *** [all] Error 1
Solution is:
cd /usr/include/mach-o
sudo wget https://gist.githubusercontent.com/mikalv/205beaae50d688c1be8816a4ac74cca8/raw/253348d8d558c7f627acef0832149bc32d6791d9/prune_trie.h
The missing libprunetrie.a
library
c++ -o ./strip.NEW \
./strip.private.o -L/usr/local/lib -lprunetrie -stdlib=libc++
ld: library not found for -lprunetrie
clang: error: linker command failed with exit code 1 (use -v to see invocation)
make[1]: *** [strip.NEW] Error 1
make: *** [all] Error 1
Solution is:
You seem to have forgotten to copy the libprunetrie.a
library to a directory the cctools makefile looks for it. On my Mac it worked fine after copying the file to /usr/local/lib/
.
The missing mach-o/arm/reloc.h
header file
In file included from /Users/mikalv/EfiWorkspace/ld64-274.2/src/other/PruneTrie.cpp:26:
/Users/mikalv/EfiWorkspace/ld64-274.2/src/abstraction/MachOFileAbstraction.hpp:591:10: error: 'mach-o/arm/reloc.h' file not found with <angled>
include; use "quotes" instead
#include <mach-o/arm/reloc.h>
^~~~~~~~~~~~~~~~~~~~
"mach-o/arm/reloc.h"
1 error generated.
** BUILD FAILED **
Solution is: Seems like it requires a header file found in cctools-895/include/mach-o/arm
. The patch for the ld64.xcodeproj/project.pbxproj
is pasted below.