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) 1 2 3 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/) 1 2 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() 1 2 3 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 ) 1 2 3 4 5 6 7 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 ) 1 2 3 4 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 ) 1 2 3 4 5 6 7 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) 1 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 ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 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" ) 1 2 3 4 5 6 7 8 9 10 11 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" ) 1 2 3 4 5 6 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

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

"); return KERN_SUCCESS; } 1 2 3 4 5 6 7 8 9 10 11 12 #include <sys/kernel_types.h> #include <sys/systm.h> kern_return_t example_start ( kmod_info_t * ki , void * d ) { printf ( "Loaded example

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

" ) ; 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__ ; 1 2 3 4 5 6 7 8 9 10 11 #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" ) 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 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> 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 <? 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.