[cmake-developers] Problem with find_path and Frameworks
Eric Wing
ewmailing at gmail.com
Wed May 25 15:44:49 EDT 2016
On 5/25/16, Harry Mallon <Harry at codexdigital.com> wrote:
> I have quite a specific problem with find_path where
> "find_path(IOKIT_INCLUDE_DIR "IOKit/pci/IOPCIDevice.h")" returns
> "/System/Library/Frameworks/Kernel.framework/Headers/IOKit/pci" rather than
> "/System/Library/Frameworks/Kernel.framework/Headers/".
>
> It is reproducible on OSX with the following CMakeLists.txt:
>
> cmake_minimum_required(VERSION 3.0)
> find_path(IOKIT_INCLUDE_DIR "IOKit/pci/IOPCIDevice.h")
> message("Path returned: ${IOKIT_INCLUDE_DIR}")
>
> Here is a patch which seems to fix it for me:
>
This is a pretty atypical situation. I’m actually not sure what the
behavior should be. But we need to be careful to not break the
existing cases. I’m a little worried that there may be things out
there relying on the existing behavior. I’m also not convinced this
actually needs a patch.
The framework header path system was hammered out over a long period
of time. There are two common use cases that it was designed to
handle:
case 1: #import <Cocoa/Cocoa.h>
find_path(COCOA_INCLUDE_DIR “Cocoa/Cocoa.h”)
# Returns something like /System/Library/Frameworks/Cocoa.framework
case 2: #include “al.h”
find_path(OPENAL_INCLUDE_DIR “al.h”)
# Returns something like /System/Library/Frameworks/OpenAL.framework/Headers
The reason for this behavior is that unlike other platforms,
frameworks are not a direct mapping to file system mapping. When
dealing with official Apple frameworks, you are expected to use case
1. But the second form is an important concession for cross-platform
libraries. The problem is that many libraries, especially 3rd party
libraries, do not end up in subdirectories with the same names on all
platforms.
For OpenGL, most Unix’s do <GL/gl.h>, but Apple does <OpenGL/gl.h>.
For OpenAL, it is crazier because it depends on which implementation
you use. Apple does <OpenAL/al.h>, OpenAL Soft does <AL/al.h>, but
others have presumes no subdirectory at all.
And a lot of third party libraries don’t have any official
conventions, so distributions do everything differently. So for
cross-platform, you are encouraged to do “Foo.h” omitting a path and
letting the build system deal with it (since CMake can do a better job
here than a massive, hand-coded mess of #ifdefs in your files.
So your case seems very atypical because you are using something
inside Kernel.framework and the header you want is not in
IOKit.framework. If it was a more typical scenario like
IOKit.framework,
I would kind of expect you to find a file in IOKit at the top level
instead to represent all your IOKit dealings, e.g.
find_path(IOKIT_INCLUDE_DIR “IOKit/IOKitLib.h”)
Then in your code you would do:
#import <IOKit/pci/IOPCIDevice.h>, and what you get back from CMake
(/System/Library/Frameworks/IOKit.framework) would be correct.
But since pci doesn’t actually seem to be directly in IOKit, but
instead the Kernel.framework subdirectory mess, I’m not sure what the
appropriate thing is. The normal native Xcode header path search
mechanism doesn’t seem to support this case and I found an old mailing
list thread suggesting that this is Apple’s way of telling you to
keep-out.
I would actually be inclined to suggest a much more generic find for
Kernel.framework and build your paths manually from there.
So either something simple like:
find_path(KERNEL_INCLUDE_DIR IOKit)
# return /System/Library/Frameworks/Kernel.framework/Headers
Or something a little more defensive to avoid possible name
collisions, but requires manual construction:
find_path(KERNEL_INCLUDE_DIR Kernel/IOKit)
# return /System/Library/Frameworks/Kernel.framework
set(KERNEL_IOKIT_INCLUDE_DIR “${KERNEL_INCLUDE_DIR}/Headers”)
-Eric
More information about the cmake-developers
mailing list