Category Archives: mac

Building an Apple OSX Kernel Module With CMake – C/C++

If you google around about how to build an osx kext you will find very few results, a few email messages saying not to bother or that it it impossible.

So what’s all the voodoo about.  A few defines, some linker options, some compiler options. Also a special info.c file and Info.plist.

Note: if you want to sign your kernel module you will need to apply to apple for a special kernel module code signing certificate.

Setup basic cmake project. We need 3.8 or newer to use BUNDLE_EXTENSION for the .kext bundle type.

cmake_minimum_required (VERSION 3.8)

project (example)

Setup some variables for later. These are both optional if you use the default system sdk or you don’t want to code sign.

set(CODE_SIGN_ID "Developer ID Application: Your Name. (XYZZYYZYZY)")
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.10.sdk/)

Add a debug preprocessor def. This is optional.

if(CMAKE_BUILD_TYPE MATCHES Debug)
        add_definitions(-DDEBUG)
endif()

Add the special preprocessor defines to access internal kernel structures.

add_definitions(
        -DKERNEL
        -DKERNEL_PRIVATE
        -DDRIVER_PRIVATE
        -DAPPLE
        -DNeXT
)

Add include directories for osx kernel headers and private headers.

include_directories(
        ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/PrivateHeaders
        ${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/Headers
)

Add an executable bundle target.

add_executable(
        ${PROJECT_NAME}
        MACOSX_BUNDLE
        example.c
        example_info.c
        Info.plist
)

Set the target bundle extension to “kext” and the plist file.

set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist)

Set a million compile options.  These were taken from a minimal xcode project.

Note: The -mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.

add_compile_options(${PROJECT_NAME}
        -x c -arch x86_64 -fmessage-length=0
        -fdiagnostics-show-note-include-stack
        -fmacro-backtrace-limit=0 -nostdinc
        -std=gnu99 -fmodules -gmodules
        -Wnon-modular-include-in-framework-module
        -Werror=non-modular-include-in-framework-module
        -fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common
        -mkernel -Wno-missing-field-initializers -Wno-missing-prototypes
        -Werror=return-type -Wdocumentation -Wunreachable-code
        -Werror=deprecated-objc-isa-usage -Werror=objc-root-class
        -Wno-missing-braces -Wparentheses -Wswitch -Wunused-function
        -Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value
        -Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas
        -Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion
        -Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32
        -Wpointer-sign -Wno-newline-eof
        -fasm-blocks -fstrict-aliasing -Wdeprecated-declarations
        -mmacosx-version-min=10.10 -Wno-sign-conversion
        -Winfinite-recursion -iquote
)

 

Add the libraries required for the kernel module and linker options.

Note: The -mmacosx-version-min=10.10 can be removed or changed to support older versions of OSX.

target_link_libraries(${PROJECT_NAME}
        "-lkmodc++"
        "-lkmod"
        "-lcc_kext"
        "-arch x86_64"
        "-mmacosx-version-min=10.10"
        "-nostdlib"
        "-Xlinker -object_path_lto"
        "-Xlinker -export_dynamic"
        "-Xlinker -kext"
)

Add a custom target to sign the kernel module.  This can be skipped if code signing isn’t needed.

add_custom_command (TARGET ${PROJECT_NAME} POST_BUILD
        COMMENT "Code Signing Kext With: ${CODE_SIGN_ID}"
        VERBATIM
        COMMAND
        /usr/bin/codesign -s "${CODE_SIGN_ID}" "${CMAKE_CURRENT_BINARY_DIR}/${PROJECT_NAME}.kext"
)

The example.c file:

#include <sys/kernel_types.h>
#include <sys/systm.h>

kern_return_t example_start(kmod_info_t * ki, void *d) {
        printf("Loaded example\n");
        return KERN_SUCCESS;
}

kern_return_t example_stop(kmod_info_t *ki, void *d) {
        printf("example unloading.\n");
        return KERN_SUCCESS;
}

The example_info.c File.  This is usually generated by xcode during the build process.

It just sets the main entry points to example_start and example_stop

#include <mach/mach_types.h>

extern kern_return_t _start(kmod_info_t *ki, void *data);
extern kern_return_t _stop(kmod_info_t *ki, void *data);
__private_extern__ kern_return_t example_start(kmod_info_t *ki, void *data);
__private_extern__ kern_return_t example_stop(kmod_info_t *ki, void *data);

__attribute__((visibility("default"))) KMOD_EXPLICIT_DECL(com.example, "1.0.0d1", _start, _stop)
__private_extern__ kmod_start_func_t *_realmain = example_start;
__private_extern__ kmod_stop_func_t *_antimain = example_stop;
__private_extern__ int _kext_apple_cc = __APPLE_CC__ ;

 

The complete cmake file.

cmake_minimum_required (VERSION 3.8)

project (example)

set(CODE_SIGN_ID "Developer ID Application: Your Name. (XYZZYYZYZY)")
set(CMAKE_OSX_SYSROOT /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX10.11.sdk/)


if(CMAKE_BUILD_TYPE MATCHES Debug)
	add_definitions(-DDEBUG)
endif()

add_definitions(
	-DKERNEL
	-DKERNEL_PRIVATE
	-DDRIVER_PRIVATE
	-DAPPLE
	-DNeXT
)

include_directories(
	${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/PrivateHeaders
	${CMAKE_OSX_SYSROOT}/System/Library/Frameworks/Kernel.framework/Headers
)

add_executable(
	${PROJECT_NAME}
	MACOSX_BUNDLE
	example.c
	example_info.c
	Info.plist
)

set_target_properties(${PROJECT_NAME} PROPERTIES BUNDLE_EXTENSION kext MACOSX_BUNDLE_INFO_PLIST ${PROJECT_SOURCE_DIR}/Info.plist)


add_compile_options(${PROJECT_NAME}
	-x c -arch x86_64 -fmessage-length=0
	-fdiagnostics-show-note-include-stack
	-fmacro-backtrace-limit=0 -nostdinc
	-std=gnu99 -fmodules -gmodules
	-Wnon-modular-include-in-framework-module
	-Werror=non-modular-include-in-framework-module
	-fno-builtin -Wno-trigraphs -msoft-float -O0 -fno-common
	-mkernel -Wno-missing-field-initializers -Wno-missing-prototypes
	-Werror=return-type -Wdocumentation -Wunreachable-code
	-Werror=deprecated-objc-isa-usage -Werror=objc-root-class
	-Wno-missing-braces -Wparentheses -Wswitch -Wunused-function
	-Wno-unused-label -Wno-unused-parameter -Wunused-variable -Wunused-value
	-Wempty-body -Wconditional-uninitialized -Wno-unknown-pragmas
	-Wno-shadow -Wno-four-char-constants -Wno-conversion -Wconstant-conversion
	-Wint-conversion -Wbool-conversion -Wenum-conversion -Wshorten-64-to-32
	-Wpointer-sign -Wno-newline-eof
	-fasm-blocks -fstrict-aliasing -Wdeprecated-declarations
	-mmacosx-version-min=10.11 -Wno-sign-conversion
	-Winfinite-recursion -iquote
)

# delete this to not code sign
target_link_libraries(${PROJECT_NAME} 
	"-lkmodc++"
	"-lkmod"
	"-lcc_kext"
	"-arch x86_64"
	"-mmacosx-version-min=10.11"
	"-nostdlib"
	"-Xlinker -object_path_lto"
	"-Xlinker -export_dynamic"
	"-Xlinker -kext"
)

The magic Info.plist file.  All references to “example” will need to match the binary and com.example items.

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>BuildMachineOSBuild</key>
	<string>15G31</string>
	<key>CFBundleDevelopmentRegion</key>
	<string>en</string>
	<key>CFBundleExecutable</key>
	<string>example</string>
	<key>CFBundleIdentifier</key>
	<string>com.example</string>
	<key>CFBundleInfoDictionaryVersion</key>
	<string>6.0</string>
	<key>CFBundleName</key>
	<string>example</string>
	<key>CFBundlePackageType</key>
	<string>KEXT</string>
	<key>CFBundleShortVersionString</key>
	<string>1.0</string>
	<key>CFBundleSupportedPlatforms</key>
	<array>
		<string>MacOSX</string>
	</array>
	<key>CFBundleVersion</key>
	<string>1</string>
	<key>DTCompiler</key>
	<string>com.apple.compilers.llvm.clang.1_0</string>
	<key>DTPlatformBuild</key>
	<string>8A218a</string>
	<key>DTPlatformVersion</key>
	<string>GM</string>
	<key>DTSDKBuild</key>
	<string>16A300</string>
	<key>DTSDKName</key>
	<string>macosx10.12</string>
	<key>DTXcode</key>
	<string>0800</string>
	<key>DTXcodeBuild</key>
	<string>8A218a</string>
	<key>NSHumanReadableCopyright</key>
	<string>Copyright © 2017 Someone. All rights reserved.</string>
	<key>OSBundleLibraries</key>
	<dict>
		<key>com.apple.kpi.bsd</key>
		<string>8.0.0</string>
		<key>com.apple.kpi.libkern</key>
		<string>8.0.0</string>
		<key>com.apple.kpi.mach</key>
		<string>8.0.0</string>
	</dict>
</dict>
</plist>

 

GitHub Repository with the example.

 

 

Cocos2dx Binary Project Mac OSX – binary template not found

Trying to build cocos2d-x-3.13.1 with a binary template for mac os x?

Problem:

 cocos new bob -p com.bob.game -l cpp -t binary
 Template named 'binary' is not found.
 Multiple templates detected!
 You can select one via -t arguments.
 Or choose one now:
 1 default

Solution:

Build the prebuilt libraries:

 cocos gen-libs -c -p mac

Build the templates

 cocos gen-templates

Now it works.

cocos new MyGame -p com.MyCompany.MyGame -l cpp -d bob -t binary

Android Studio Mac Extremely Slow

Downloaded the latest Android Studio:  2.1.3 for mac and it won’t boot or run anything.

Seems first off you need to run the emulator on sudo or it will segfault.  After launching from Android Studio you see it tried to run something like: /Users/user/Library/Android/sdk/tools/emulator -netdelay none -netspeed full -avd Galaxy_Nexus_API_22. end then segfaults.

Copy the command and run:

sudo /Users/user/Library/Android/sdk/tools/emulator -netdelay none -netspeed full -avd Galaxy_Nexus_API_22

So now it doesnt’ boot or appears to boot but takes days… you reboot because you can’t kill the thing either.  Maybe you have installed Virtual Box on you machine at some point and it turns out the kernel modules form virtual box interfere with the intel/google/android emulator( com.intel.kext.intelhaxm )

Solutions:

Uninstall VirtualBox…

Or

sudo kextunload -b org.virtualbox.kext.VBoxUSB
sudo kextunload -b org.virtualbox.kext.VBoxNetFlt
sudo kextunload -b org.virtualbox.kext.VBoxNetFlt
sudo kextunload -b org.virtualbox.kext.VBoxNetAdp
sudo kextunload -b org.virtualbox.kext.VBoxDrv

Enjoy the still slow emulator but it seems to work…