Configure Cmake to only use OBJC linker only on MacOS (with PCH)

Im working on a cross platform project that I want to be compatible with MacOS, Linux and Windows however im encountering a weird issue with Cmake.

Within my project I have Objc++ .mm files that I want only compiled on MacOS and skipped on the other platforms. I followed this link to get it to compile with my C++ and PCH files, however that sets the whole project as OBJC++/OBJC (which wont compile under Windows or Linux).

Someone suggested I use this within the check for APPLE:

set_source_files_properties(${SOURCE_FILES} PROPERTIES
        COMPILE_FLAGS "-x objective-c++")

However this option doesnt allow PCH files to be used with the OBJC source files and results with this error: error: Objective-C was disabled in PCH file but is currently enabled

I also tried using the enable_language(OBJC) and enable_language(OBJCXX) within the APPLE check (instead of the suggestion), and that results in this error:

CMake Error: Error required internal CMake variable not set, cmake may not be built correctly.
Missing variable is:
CMAKE_OBJC_COMPILE_OBJECT

Basically, is there a way to tell cmake “I want you to compile and use PCH with OBJC ONLY on MacOS, and skip OBJC on other platforms” without setting the whole project to OBJC?

That would have been what I would have suggested. Perhaps if you show the project’s CMakeLists.txt, then we might be able to better see what the problem may be.

Thanks for the reply!

I have two issues/questions now so I’ve labeled each one to avoid confusion.

Unfortunately I’m not able to upload my cmake file as I get the error “new users cannot upload files” which is totally understandable. That is why I’ve chosen to copy paste the contents:


cmake_minimum_required(VERSION 3.19)
project(RcEngine LANGUAGES CXX C)

set(CMAKE_CXX_STANDARD 17)

file(GLOB source_headers
        "*.h"
        "*.hpp"
        "external/glm/glm/*.cpp"
        "external/glm/glm/*.hpp"
        "external/glm/glm/*.inl"
        "external/GLFW/include/GLFW/*.h"
        "external/imgui/*.h"
        "external/imgui/*.cpp"
        "external/spdlog/*.h"
        "external/entt/include/*.hpp"
        "external/yaml-cpp/include/*.h"
        "external/yaml-cpp/include/*.cpp"
        "external/imguizmo/*.cpp"
        "external/imguizmo/*.h"
        )

include_directories("external/imguizmo")
include_directories("external/glm/glm")
include_directories("external/imgui")
include_directories(SYSTEM "external/glad/include")
include_directories("external/SOIL2")
include_directories(SYSTEM "external/entt/include")
include_directories("external/yaml-cpp/include")
include_directories("src")

add_subdirectory(external/imguizmo)
add_subdirectory(external/spdlog)
add_subdirectory(external/imgui)
add_subdirectory(external/SOIL2)
add_subdirectory(external/yaml-cpp)
add_subdirectory(external/corrosion)

#GLFW--------------------------------------------
set(GLFW_BUILD_DOCS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_TESTS OFF CACHE BOOL "" FORCE)
set(GLFW_BUILD_EXAMPLES OFF CACHE BOOL "" FORCE)
add_subdirectory(external/GLFW/)
add_subdirectory(external/glad/)
#------------------------------------------------


#Pass arguments----------------------------------------------------
if(WIN32)
    add_definitions(-DRC_PLATFORM_WINDOWS)
    set(WINDOW
        src/Platform/Windows/WindowsWindow.cpp
        src/Platform/Windows/WindowsWindow.h
        src/Platform/Mac/MacUtils.h
        )
    set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /MD")
    set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} /MDd")
    include_directories(GL)

endif(WIN32)
if(APPLE)
    enable_language(OBJC)
    enable_language(OBJCXX)

    #set(CMAKE_C_FLAGS "-x objective-c")
    add_definitions(-DRC_PLATFORM_MAC)
    add_definitions(-DRC_PLATFORM_UNIX)
    set(WINDOW
        src/Platform/Mac/MacWindow.cpp
        src/Platform/Mac/MacWindow.h
        src/Platform/Mac/MacUtils.mm
            )
    set(METAL
            src/Platform/Metal/MetalBuffer.mm
            src/Platform/Metal/MetalBuffer.h src/Platform/Metal/Metal.h)
    set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -framework AppKit Metal")
endif(APPLE)

add_definitions(-DRC_BUILD_DLL)
add_definitions(-DGLFW_INCLUDE_NONE)

add_definitions(-DRC_DEBUG)

if (CMAKE_BUILD_TYPE EQUAL "Debug")
    add_definitions(-DRC_DEBUG)
endif()
#SOURCE-------------------------------------------------------------

set(SOURCE_FILES
        src/RcEngine/Core/EntryPoint.h src/RcEngine/Core/Log.cpp
        src/RcEngine/Core/Log.h src/RcEngine/Events/Event.h
        src/RcEngine/Events/ApplicationEvent.h src/RcEngine/Events/KeyEvent.h
        src/RcEngine/Events/MouseEvent.h
        src/RcEngine/Core/Window.h ${WINDOW}
        src/RcEngine/Core/LayerStack.cpp src/RcEngine/Core/LayerStack.h
        src/RcEngine/Core/Layer.cpp src/RcEngine/Core/Layer.h
        src/RcEngine/Core/Input.h src/Platform/Mac/MacInput.cpp
        src/Platform/Mac/MacInput.h src/RcEngine/Core/keycodes.h
        src/RcEngine/Core/MouseButtonCodes.h
        )
#GUI---------------------------------------------------------------
set(GUI
        src/RcEngine/ImGui/ImGuiLayer.cpp
        src/RcEngine/ImGui/ImGuiLayer.h
        src/RcEngine/ImGui/ImGuiBuild.cpp
)
#RENDERER----------------------------------------------------------
set(RENDERER
        src/RcEngine/Renderer/Shader.h src/RcEngine/Renderer/Shader.cpp
        src/RcEngine/Renderer/Buffer.h
        src/RcEngine/Renderer/Buffer.cpp src/RcEngine/Renderer/Renderer.h
        src/RcEngine/Renderer/Renderer.cpp
        src/RcEngine/Renderer/VertexArray.h src/RcEngine/Renderer/VertexArray.cpp
        src/RcEngine/Renderer/RenderAPI.h src/RcEngine/Renderer/RenderAPI.cpp
        src/RcEngine/Renderer/RenderCommand.h src/RcEngine/Renderer/RenderCommand.cpp
        src/RcEngine/Renderer/Camera.h src/RcEngine/Renderer/OrthoCamera.cpp
        src/RcEngine/Renderer/OrthoCamera.h
        src/RcEngine/Renderer/GraphicsContext.h
        src/RcEngine/Renderer/GraphicsContext.cpp
        src/RcEngine/Renderer/Texture.cpp src/RcEngine/Renderer/Texture.h
        src/RcEngine/Renderer/OrthoCameraController.h
        src/RcEngine/Renderer/OrthoCameraController.cpp
        src/RcEngine/Renderer/ProjectionCamera.cpp src/RcEngine/Renderer/ProjectionCamera.h
        src/RcEngine/Renderer/Renderer2D.cpp src/RcEngine/Renderer/Renderer2D.h
        src/RcEngine/Renderer/IsoCameraController.cpp src/RcEngine/Renderer/IsoCameraController.h
        src/RcEngine/Renderer/SubTexture2D.h src/RcEngine/Renderer/SubTexture2D.cpp
        src/RcEngine/Renderer/FrameBuffer.cpp src/RcEngine/Renderer/FrameBuffer.h
        src/RcEngine/Renderer/EditorCamera.cpp src/RcEngine/Renderer/EditorCamera.h)
#CORE--------------------------------------------------------------
set(CORE
        src/RcEngine.h src/rcpch.cpp src/rcpch.h
        src/RcEngine/Core/Assert.h src/RcEngine/Core/Core.h
        src/RcEngine/Core/Application.h src/RcEngine/Core/Application.cpp
        src/RcEngine/Core/Timestep.h src/RcEngine/Core/Window.cpp src/RcEngine/Math/Math.cpp
        src/RcEngine/Math/Math.h)
#OPENGL------------------------------------------------------------
set(OPENGL_CXT
        src/Platform/OpenGL/OpenGLUtils.cpp src/Platform/OpenGL/OpenGLUtils.h
        src/Platform/OpenGL/OpenGLContext.h src/Platform/OpenGL/OpenGLContext.cpp
        src/Platform/OpenGL/OpenGLBuffer.h src/Platform/OpenGL/OpenGLBuffer.cpp
        src/Platform/OpenGL/OpenGLVertexArray.h src/Platform/OpenGL/OpenGLRenderAPI.h
        src/Platform/OpenGL/OpenGLRenderAPI.cpp src/Platform/OpenGL/OpenGLVertexArray.cpp
        src/Platform/OpenGL/OpenGLShader.cpp src/Platform/OpenGL/OpenGLShader.h
        src/Platform/OpenGL/OpenGLTexture.cpp src/Platform/OpenGL/OpenGLTexture.h
        src/Platform/OpenGL/OpenGLFrameBuffer.cpp src/Platform/OpenGL/OpenGLFrameBuffer.h)
#SCENE-------------------------------------------------------------
set(SCENE
        src/RcEngine/Scene/Scene.h
        src/RcEngine/Scene/Scene.cpp
        src/RcEngine/Scene/Component.h src/RcEngine/Scene/Entity.h
        src/RcEngine/Scene/Entity.cpp src/RcEngine/Scene/SceneCamera.h
        src/RcEngine/Scene/SceneCamera.cpp src/RcEngine/Scene/ScriptableEntity.h
        src/RcEngine/Scene/SceneSerializer.cpp src/RcEngine/Scene/SceneSerializer.h)
#UTILS-------------------------------------------------------------
set(UTILS
        src/RcEngine/Utils/PlatformUtils.h)
#DEBUG-------------------------------------------------------------
set(DEBUG_FILE
        src/RcEngine/Debug/Instrumentor.h)
#------------------------------------------------------------------
if(APPLE)
    set(NETWORK src/RcEngine/Network/Network.h)
endif(APPLE)

#------------------------------------------------------------------
add_library(rcengine STATIC
        ${CORE}
        ${RENDERER}
        ${OPENGL_CXT}
        ${SOURCE_FILES}
        ${GUI}
        ${METAL}
        ${source_headers}
        ${GLOB}
        ${NETWORK}
        ${SCENE}
        ${UTILS}
        )
#------------------------------------------------------------------
if (CMAKE_BUILD_TYPE EQUAL "DEBUG")
    message("DEBUG BUILD")
    add_library(rcengine STATIC
            ${DEBUG_FILE}
            )
endif()
#------------------------------------------------------------------


target_precompile_headers(rcengine PRIVATE src/rcpch.h)


#link with libraries-------------------
find_package(OpenGL REQUIRED)
find_package(spdlog)
find_package(imgui)
find_package(soil2)
find_package(GLFW)
find_package(glad)
find_package(entt)
find_package(imguizmo)
find_package(yaml-cpp)

#Rust library link---------------------
if(APPLE)
    corrosion_import_crate(MANIFEST_PATH external/RcNetwork/Cargo.toml)
    set(SDK_LOC /Volumes/MacStorage/sdk)
    set_property(
            TARGET rc_network
            APPEND
            PROPERTY CORROSION_ENVIRONMENT_VARIABLES
            "STEAM_SDK_LOCATION=${SDK_LOC}"
    )
endif()
#--------------------------------------

target_link_libraries(rcengine
        glfw
        glad
        spdlog
        OpenGL::GL
        imgui
        soil2
        yaml-cpp
        imguizmo
        )

if(APPLE)
    target_link_libraries(rcengine
            rc_network
            )
endif()
#--------------------------------------


target_include_directories(rcengine PUBLIC $(CMAKE_CURRENT_SOURCE_DIR))

When I run this this cmakelists.txt it results in the error:CMake Error: Error required internal CMake variable not set, cmake may not be built correctly. Missing variable is: CMAKE_OBJC_COMPILE_OBJECT

So I tried some other approaches and started looking at how other projects/game engines handle Metal with C++ and I found one project called SirMetal that uses embedded Objc++ code from within a C++ source file by using:

set_source_files_properties(${SOURCE_FILES} PROPERTIES
        COMPILE_FLAGS "-x objective-c++")

within its Cmake.
However when I try to use this approach in my project I end up with the Cmake error: error: Objective-C was disabled in PCH file but is currently enabled even though when I was testing it I had the whole project set as OBJC like so: project(RcEngine LANGUAGES C CXX OBJC OBJCXX). This to me would be the ideal approach since this implementation wouldn’t need Objc++ wrappers for C++, but it doesn’t look like precompiled headers would be supported. Would it be possible to do this approach with precompiled headers with cmake?

Thanks

That’s a huge and still incomplete project. I suggest you try to cut down that project to the most minimal thing you can that still reproduces the error. That activity alone will likely help you identify the problem.

I notice that the error message mentions OBJC, but you haven’t enabled that language in you top level project() command. That may be related, but you will need to investigate that.

You shouldn’t need to add the source file property you mentioned. That is an indicator of something not being set up correctly in the project. The PCH aspect could be a complication. I seem to recall recent bug reports and discussions mentioning PCH and I think OBJC and/or OBJCXX. Sorry I can’t be any more specific than that, but you could try searching the CMake issue tracker for any relevant info.

Thanks for the advice!!!

I didn’t enable OBJCXX in my top level Project() command due to the fact that it would set the whole project as Objc. Would the command enable_language() set it so that Objc/Objcxx only compiles on MacOS?

Again, thanks so much for the reply and suggestions!!!

This arrangement should be fine:

project(RcEngine LANGUAGES CXX C)
if(APPLE)
    enable_language(OBJC)
endif()

I’m not saying this is what you should do, but it may be helpful in investigating your problem. I reiterate that you really should try to strip your project down to something minimal that still reproduces your problem. I’m pretty sure you will find the error if you do that.