All posts by goodbits

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…

 

 

How to detect if your system tray icon has gone missing, C/C++, Win32

The Problem:

Sometimes if either the desktop crashes or windows decides to go wrong for whatever reason, it re-creates the system tray. There is no way to detect when that happens and your icon is now missing but your system tray application is still running.

The Solution:

Windows does send a windows message to be notified when the system tray is being created.  It won’t be sent to you unless you register to receive it.

To register to receive the message do the following and store the ID that is returned. The simplest way to do this is to store it in a global variable.

const int uTaskbarCreatedMsg = RegisterWindowMessageA("TaskbarCreated");

Then later on in your windows message loop handle the message.

LRESULT CALLBACK WndProc(HWND w, UINT msg, WPARAM wparam, LPARAM lparam)
{
    // ... handle other messages
    if (msg == uTaskbarCreatedMsg) {
        // Destroy any existing icon and recreate it
        CreateSystemTrayIcon();
        return 0;
    }
    // ... default message handling
}

 

Related Links

Related Searches

  • how to detect if the system tray is gone msdn
  • how to detect if the system tray is gone
  • systray icon restart after explore.exe crashes
  • catch explore restart message msdn
  • win32 message for when explorer.exe starts msdn
  • windows message for when explorer.exe starts msdn
  • systray icon dissapears after sleep
  • windows message for when system awakes from sleep

How to get rid of unwanted directories from an subversion checkout

The Problem

Using svn if you’ve checked out a tree but didn’t want the entire tree how can you get rid of some of the subfolders.  This is generally a problem if there are some really big folder slowing down diff or other operations in the tree.

Example

You have checked out http://server/trunk but there is a gigantic folder that was checked out and you want to remove it from the checkout but not svn continues to annoy you saying that you’ve deleted it. Further if you simply delete the folder it will show as deleted every time run svn diff.

svn co http://server/trunk

Resulting in

trunk/one
trunk/two
trunk/three

The Solution

cd trunk
rm -rf three
svn up -N three

If That Doesn’t Work

rm -rf three
svn update --set-depth empty three

The folder will still be there but it will not cause problems with everyday life.