理念
我正在尝试用C实现一个游戏引擎。
我正在使用macOS进行开发(arm-64架构)。我想创建一个使用Foundation框架的窗口。
CMakeLists.txt使用C和Objective-C语言,我想构建一个只包含Objective-C代码的库,然后在我的C代码中使用这个库(可能包括头文件)。最终结果应该是一个C可执行文件。
项目结构
[src]
├── [Draw]
├── Window.cpp
├── Window.h
└── [WindowBuilder]
├── WindowBuilder.cpp
├── WindowBuilder.h
└── [macOS]
├── WindowBuilderObjC.h
└── WindowBuilderObjC.mm
├── [Utils]
└── Size.h
├── main.cpp
└── CMakeLists.txt
字符串
源代码
src/Draw/Window.h
#include <iostream>
#include <Utils/Size.h>
#include "WindowBuilder/WindowBuilder.h"
#pragma once
namespace Draw
{
class Window
{
private:
bool _isPresented;
Utils::Size _size = Utils::Size(0, 0);
WindowBuilder::WindowBuilder *_builder;
Window();
~Window() = default;
public:
// Public static member function to access the singleton instance
static Window &Instance()
{
// Guaranteed to be initialized once
static Window instance;
return instance;
}
// Delete the copy constructor and assignment operator
Window(const Window &) = delete;
Window &operator=(const Window &) = delete;
void SetSize(Utils::Size size);
void DrawWindow();
};
}
型
src/Draw/Window.cpp
#include "Window.h"
namespace Draw
{
Window::Window()
{
_builder = &WindowBuilder::WindowBuilder::Instance();
}
void Window::SetSize(Utils::Size size)
{
_size = size;
}
void Window::DrawWindow()
{
std::cout << "Draw window with size: [" << _size.GetWidth() << ":" << _size.GetHeight() << "]" << std::endl;
_builder->BuildWindow(_size);
}
}
型
src/WindowBuilder/WindowBuilder.h
// General
#include <iostream>
// Internal
#include <Utils/Size.h>
#include <Draw/WindowBuilder/macOS/WindowBuilderObjC.h>
#pragma once
namespace WindowBuilder
{
class WindowBuilder
{
private:
bool _isPresented;
WindowBuilder() = default;
~WindowBuilder() = default;
public:
static WindowBuilder &Instance()
{
// Guaranteed to be initialized once
static WindowBuilder instance;
return instance;
}
// Delete the copy constructor and assignment operator
WindowBuilder(const WindowBuilder &) = delete;
WindowBuilder &operator=(const WindowBuilder &) = delete;
void BuildWindow(Utils::Size size);
};
}
型
src/WindowBuilder/WindowBuilder.cpp
#include "WindowBuilder.h"
namespace WindowBuilder
{
void WindowBuilder::BuildWindow(Utils::Size size)
{
buildWindowWithSize(size);
}
}
型
src/Draw/WindowBuilder/macOS/WindowBuilderObjC.h
#import <Cocoa/Cocoa.h>
#import "Utils/Size.h"
@interface WindowBuilderObjC : NSObject
- (void)buildWindowWithSize:(Utils::Size)size;
@end
@interface WindowDelegate : NSObject <NSWindowDelegate>
@end
@implementation WindowDelegate
- (BOOL)windowShouldClose:(id)sender
{
[NSApp terminate:nil];
return YES;
}
@end
型
src/Draw/WindowBuilder/macOS/WindowBuilderObjC.mm
#import "WindowBuilderObjC.h"
@implementation WindowBuilderObjC
- (void)buildWindowWithSize:(Utils::Size)size
{
@autoreleasepool
{
[NSApplication sharedApplication];
NSRect frame = NSMakeRect(0, 0, 800, 600);
NSUInteger style = NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskResizable;
NSWindow *window = [[NSWindow alloc] initWithContentRect:frame styleMask:style backing:NSBackingStoreBuffered defer:NO];
[window setTitle:@"My Window"];
[window center];
WindowDelegate *delegate = [[WindowDelegate alloc] init];
[window setDelegate:delegate];
[window makeKeyAndOrderFront:nil];
[NSApp run];
}
}
@end
型
src/main.cpp
#include <iostream>
#include <Draw/Window.h>
#include <Utils/Size.h>
int main()
{
std::cout << "Hello World" << std::endl;
Utils::Size size(600, 800);
auto &window = Draw::Window::Instance();
window.SetSize(size);
window.DrawWindow();
}
型
CMakeLists.txt
cmake_minimum_required(VERSION 3.16)
project(GameEngine LANGUAGES CXX OBJC OBJCXX)
set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
# enable_language(OBJC)
# enable_language(OBJCXX)
add_executable(Engine src/main.cpp)
add_library(UtilsLib SHARED
src/Utils/Size.h
)
set_target_properties(UtilsLib PROPERTIES LINKER_LANGUAGE CXX)
add_library(WindowBuilderObjCLib SHARED
src/Draw/WindowBuilder/macOS/WindowBuilderObjC.h
src/Draw/WindowBuilder/macOS/WindowBuilderObjC.mm
)
target_include_directories(WindowBuilderObjCLib
PRIVATE
${CMAKE_CURRENT_SOURCE_DIR}/src/Draw/WindowBuilder/macOS
)
target_link_libraries(WindowBuilderObjCLib
PRIVATE "-framework Cocoa"
PRIVATE "-framework Foundation"
PRIVATE "-framework AppKit"
)
# Set the language for the library to Objective-C++
set_target_properties(WindowBuilderObjCLib PROPERTIES
LINKER_LANGUAGE "OBJCXX"
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_ARC YES
XCODE_ATTRIBUTE_CLANG_ENABLE_MODULES YES
XCODE_ATTRIBUTE_CLANG_ENABLE_OBJC_WEAK YES
)
add_library(DrawLib STATIC
src/Draw/Window.h
src/Draw/Window.cpp
)
target_sources(DrawLib
PRIVATE
src/Draw/WindowBuilder/WindowBuilder.h
src/Draw/WindowBuilder/WindowBuilder.cpp
)
target_sources(DrawLib
PUBLIC
src/Draw/Window.h
src/Draw/Window.cpp
)
set_target_properties(DrawLib PROPERTIES LINKER_LANGUAGE CXX)
find_library(FOUNDATION_FRAMEWORK Foundation)
# Link against required frameworks and libraries
target_link_libraries(DrawLib
PRIVATE ${FOUNDATION_FRAMEWORK}
"-framework AppKit"
"-framework CoreGraphics"
"-lobjc"
)
find_package(OpenGL REQUIRED COMPONENTS OpenGL)
include_directories(${CMAKE_SOURCE_DIR}/src)
add_subdirectory(src/Draw/WindowBuilder/macOS)
# Link the DrawLib and UtilsLib targets to the Engine target
target_link_libraries(Engine PRIVATE
WindowBuilderObjCLib
DrawLib
UtilsLib
OpenGL::GL
${FOUNDATION_FRAMEWORK}
)
型
错误
似乎当我将Window.h包含到main.cpp中时,编译器会在可可/Cocoa.h文件中查找符号,并找到 Objective-C 符号而不是 C++。
错误如下:
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/Window.cpp:1:
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/Window.h:4:
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/WindowBuilder/WindowBuilder.h:6:
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/WindowBuilder/macOS/WindowBuilderObjC.h:1:
[build] In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Cocoa.framework/Headers/Cocoa.h:12:
[build] In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:8:
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:601:1: error: expected unqualified-id
[build] @class NSString, Protocol;
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/WindowBuilder/WindowBuilder.cpp:1:
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/WindowBuilder/WindowBuilder.h:6:
[build] ^
[build] In file included from /Users/user/MySource/GameEngine_Vulkan/src/Draw/WindowBuilder/macOS/WindowBuilderObjC.h:1:
[build] In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Cocoa.framework/Headers/Cocoa.h:12:
[build] In file included from /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/Foundation.h:8:
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:601:1: error: expected unqualified-id
[build] @class NSString, Protocol;
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:603:9: error: unknown type name 'NSString'
[build] typedef NSString * NSExceptionName NS_TYPED_EXTENSIBLE_ENUM;
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:603:9: error: unknown type name 'NSString'
[build] typedef NSString * NSExceptionName NS_TYPED_EXTENSIBLE_ENUM;
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:604:9: error: unknown type name 'NSString'
[build] typedef NSString * NSRunLoopMode NS_TYPED_EXTENSIBLE_ENUM;
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:604:9: error: unknown type name 'NSString'
[build] typedef NSString * NSRunLoopMode NS_TYPED_EXTENSIBLE_ENUM;
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:606:19: error: unknown type name 'NSString'
[build] FOUNDATION_EXPORT NSString *NSStringFromSelector(SEL aSelector);
[build] ^
[build] /Applications/Xcode.app/Contents/Developer/Platforms/MacOSX.platform/Developer/SDKs/MacOSX13.3.sdk/System/Library/Frameworks/Foundation.framework/Headers/NSObjCRuntime.h:606:19: error: unknown type name 'NSString'
[build] FOUNDATION_EXPORT NSString *NSStringFromSelector(SEL aSelector);
[build] ^
...
型
问题
我可以使用Objective-C构建一个包含可可lib的独立库(可能),并且它将具有公共接口,以便我可以在C++项目中使用它吗?
1条答案
按热度按时间xfb7svmp1#
因此,对于任何正在寻找这种实现的人来说:
1.用Objective-C编写代码,提供你想要的功能(在我的例子中,在macOS中创建一个窗口):
WindowBuilderObjC.h
字符串
WindowBuilderObjC.mm
型
2.使用关键字 extern“C” 创建一个带有C头的文件(仍然是Objective-C)(因此它们可以在C代码中使用):
WindowBuilderObjCWrapper.mm
型
3.修改CMakeLists.txt,从Objective-C文件创建模块库:
CMakeLists.txt
型
4.在C++中按照以下步骤操作:
4.1.使用 dlfcn.h lib打开库:
型
4.2.(可选)使用 boost lib检查打开的库是否包含所需的函数签名:
型
4.3.(可选)在将要使用库函数的C++类中创建方法签名(您也可以基于签名构建自己的实现):
型
4.4.从库中获取函数,并将其转换为合适的签名:
型
4.5.使用导入库中的Objective-C函数(通过C++头文件):
型
就是这样,希望对大家有用。