Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add moltenvk/1.1.1 #4634

Merged
merged 21 commits into from
Feb 24, 2021
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
229 changes: 229 additions & 0 deletions recipes/moltenvk/all/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,229 @@
cmake_minimum_required(VERSION 3.12)
project(MoltenVK)

include(conanbuildinfo.cmake)
conan_basic_setup(TARGETS)

if(NOT (CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Where did you find this cmake file?

Copy link
Contributor Author

@SpaceIm SpaceIm Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I wrote it from scratch
#4634 (comment)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good job!

CMAKE_SYSTEM_NAME STREQUAL "iOS" OR
CMAKE_SYSTEM_NAME STREQUAL "tvOS"))
message(FATAL_ERROR "MoltenVK only supports MacOS, iOS and tvOS")
endif()

option(MVK_WITH_SPIRV_TOOLS "Build MoltenVK without the MVK_EXCLUDE_SPIRV_TOOLS build setting" ON)
option(MVK_BUILD_SHADERCONVERTER_TOOL "Build MoltenVKShaderConverter" ON)

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED ON)

# PIC required for objects targets linked into shared MoltenVK
if(BUILD_SHARED_LIBS)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif()

# Required Apple Frameworks
find_library(METAL_FRAMEWORK Metal)
SpaceIm marked this conversation as resolved.
Show resolved Hide resolved
if(NOT METAL_FRAMEWORK)
message(FATAL_ERROR "Metal framework not found")
endif()
find_library(FOUNDATION_FRAMEWORK Foundation)
if(NOT FOUNDATION_FRAMEWORK)
message(FATAL_ERROR "Foundation framework not found")
endif()
find_library(QUARTZ_CORE_FRAMEWORK QuartzCore)
if(NOT QUARTZ_CORE_FRAMEWORK)
message(FATAL_ERROR "QuartzCore framework not found")
endif()
find_library(APPKIT_FRAMEWORK AppKit)
if(NOT APPKIT_FRAMEWORK)
message(FATAL_ERROR "AppKit framework not found")
endif()
find_library(IOSURFACE_FRAMEWORK IOSurface)
if(NOT IOSURFACE_FRAMEWORK)
message(FATAL_ERROR "IOSurface framework not found")
endif()
if(CMAKE_SYSTEM_NAME STREQUAL "Darwin")
find_library(IO_OR_UI_KIT_FRAMEWORK IOKit)
if(NOT IO_OR_UI_KIT_FRAMEWORK)
message(FATAL_ERROR "IOKit framework not found")
endif()
else()
find_library(IO_OR_UI_KIT_FRAMEWORK UIKit)
if(NOT IO_OR_UI_KIT_FRAMEWORK)
message(FATAL_ERROR "UIKit framework not found")
endif()
endif()

set(MVK_DIR ${CMAKE_CURRENT_SOURCE_DIR}/source_subfolder)
set(MVK_INSTALL_TARGETS "")

# MoltenVKCommon
# * direct dependencies:
# - external: None
# - internal: None
# - frameworks: Foundation
file(GLOB MVK_COMMON_SOURCES ${MVK_DIR}/common/*.mm)
add_library(MoltenVKCommon OBJECT ${MVK_COMMON_SOURCES})
target_include_directories(MoltenVKCommon PUBLIC ${MVK_DIR}/common)
target_compile_definitions(MoltenVKCommon PRIVATE $<$<CONFIG:Debug>:DEBUG=1>)
target_link_libraries(MoltenVKCommon PRIVATE ${FOUNDATION_FRAMEWORK})

# MoltenVKShaderConverter
# * direct dependencies:
# - external: spirv-cross, glslang, and spirv-tools (optional)
# - internal: MoltenVKCommon
# - frameworks: Foundation
file(GLOB MVK_SC_COMMON_SOURCES ${MVK_DIR}/MoltenVKShaderConverter/common/*.cpp)
if(MVK_VERSION VERSION_LESS "1.1.0")
file(GLOB MVK_SC_CONVERTERS_SOURCES
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/*.cpp
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/*.mm
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/*.cpp
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/*.mm
)
else()
file(GLOB MVK_SC_CONVERTERS_SOURCES
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverter/*.cpp
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverter/*.mm
)
endif()
add_library(MoltenVKShaderConverter OBJECT ${MVK_SC_COMMON_SOURCES} ${MVK_SC_CONVERTERS_SOURCES})
target_include_directories(MoltenVKShaderConverter
PRIVATE ${MVK_DIR}/MoltenVKShaderConverter/common
INTERFACE ${MVK_DIR}/MoltenVKShaderConverter
)
if(MVK_VERSION VERSION_LESS "1.1.0")
target_include_directories(MoltenVKShaderConverter PRIVATE
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter
)
endif()
target_link_libraries(MoltenVKShaderConverter
PRIVATE
CONAN_PKG::glslang
MoltenVKCommon
${FOUNDATION_FRAMEWORK}
PUBLIC
CONAN_PKG::spirv-cross
)
if(NOT MVK_WITH_SPIRV_TOOLS)
target_compile_definitions(MoltenVKShaderConverter PRIVATE MVK_EXCLUDE_SPIRV_TOOLS)
target_link_libraries(MoltenVKShaderConverter PRIVATE CONAN_PKG::spirv-tools)
endif()

# MoltenVKShaderConverterTool
# * direct dependencies:
# - external: None
# - internal: MoltenVKShaderConverter and MoltenVKCommon
# - frameworks: Metal and Foundation
if(MVK_BUILD_SHADERCONVERTER_TOOL)
file(GLOB MVK_SCT_SOURCES
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverterTool/*.cpp
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverterTool/*.mm
)
add_executable(MoltenVKShaderConverterTool ${MVK_SCT_SOURCES})
set_property(TARGET MoltenVKShaderConverterTool PROPERTY OUTPUT_NAME "MoltenVKShaderConverter")
target_include_directories(MoltenVKShaderConverterTool PRIVATE
${MVK_DIR}/MoltenVKShaderConverter/common
)
if(MVK_VERSION VERSION_LESS "1.1.0")
target_include_directories(MoltenVKShaderConverterTool PRIVATE
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter
)
else()
target_include_directories(MoltenVKShaderConverterTool PRIVATE
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverter
)
endif()
target_link_libraries(MoltenVKShaderConverterTool PRIVATE
MoltenVKCommon
MoltenVKShaderConverter
${METAL_FRAMEWORK}
${FOUNDATION_FRAMEWORK}
)
list(APPEND MVK_INSTALL_TARGETS MoltenVKShaderConverterTool)
endif()

# MoltenVK
# * direct dependencies:
# - external: cereal, spirv-cross and vulkan-headers (+ vulkan-portability if moltenvk < 1.1.0)
# - internal: MoltenVKShaderConverter and MoltenVKCommon
# - frameworks: Foundation, Metal, QuartzCore, AppKit, IOSurface + IOKit (Macos) or UIKit (iOS/tvOS)
file(GLOB_RECURSE MVK_SOURCES
${MVK_DIR}/MoltenVK/*.m
${MVK_DIR}/MoltenVK/*.mm
${MVK_DIR}/MoltenVK/*.cpp
)
add_library(MoltenVK ${MVK_SOURCES})
target_include_directories(MoltenVK PRIVATE
${MVK_DIR}/MoltenVK/MoltenVK/API
${MVK_DIR}/MoltenVK/MoltenVK/Commands
${MVK_DIR}/MoltenVK/MoltenVK/GPUObjects
${MVK_DIR}/MoltenVK/MoltenVK/Layers
${MVK_DIR}/MoltenVK/MoltenVK/OS
${MVK_DIR}/MoltenVK/MoltenVK/Utility
${MVK_DIR}/MoltenVK/MoltenVK/Vulkan
)
target_link_libraries(MoltenVK
PRIVATE
CONAN_PKG::cereal
CONAN_PKG::spirv-cross
MoltenVKCommon
MoltenVKShaderConverter
${FOUNDATION_FRAMEWORK}
${QUARTZ_CORE_FRAMEWORK}
${APPKIT_FRAMEWORK}
${IO_OR_UI_KIT_FRAMEWORK}
PUBLIC
CONAN_PKG::vulkan-headers
${METAL_FRAMEWORK}
${IOSURFACE_FRAMEWORK}
)
if(MVK_VERSION VERSION_LESS "1.1.0")
target_link_libraries(MoltenVK PUBLIC CONAN_PKG::vulkan-portability)
endif()
target_compile_options(MoltenVK PRIVATE
-Wno-unguarded-availability-new
-Wno-deprecated-declarations
-Wno-nonportable-include-path
)
list(APPEND MVK_INSTALL_TARGETS MoltenVK)

install(
TARGETS ${MVK_INSTALL_TARGETS}
BUNDLE DESTINATION ${CMAKE_INSTALL_BINDIR}
RUNTIME DESTINATION ${CMAKE_INSTALL_BINDIR}
LIBRARY DESTINATION ${CMAKE_INSTALL_LIBDIR}
ARCHIVE DESTINATION ${CMAKE_INSTALL_LIBDIR}
)

if(BUILD_SHARED_LIBS)
install(
FILES ${MVK_DIR}/MoltenVK/icd/MoltenVK_icd.json
DESTINATION ${CMAKE_INSTALL_LIBDIR}
)
endif()

file(GLOB MVK_PUBLIC_HEADERS ${MVK_DIR}/MoltenVK/MoltenVK/API/*.h)
install(
FILES ${MVK_PUBLIC_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MoltenVK
)

if(MVK_VERSION VERSION_LESS "1.1.0")
file(GLOB MVK_SC_PUBLIC_HEADERS
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/*Conversion.h
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKGLSLToSPIRVConverter/*Converter.h
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/*Conversion.h
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKSPIRVToMSLConverter/*Converter.h
)
else()
file(GLOB MVK_SC_PUBLIC_HEADERS
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverter/*Conversion.h
${MVK_DIR}/MoltenVKShaderConverter/MoltenVKShaderConverter/*Converter.h
)
endif()
install(
FILES ${MVK_SC_PUBLIC_HEADERS}
DESTINATION ${CMAKE_INSTALL_INCLUDEDIR}/MoltenVKShaderConverter
)
8 changes: 8 additions & 0 deletions recipes/moltenvk/all/conandata.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
sources:
"1.1.1":
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

1.1.2 was released 6 hours ago, should we add this new version?

Copy link
Contributor Author

@SpaceIm SpaceIm Feb 23, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It requires vulkan-headers 1.2.170, not yet in CCI. And I prefer to wait sdk tag of this vulkan-headers version. Usually each MoltenVK version refers to a SDK version of Vulkan.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

url: "https://github.com/KhronosGroup/MoltenVK/archive/v1.1.1.tar.gz"
sha256: "cd1712c571d4155f4143c435c8551a5cb8cbb311ad7fff03595322ab971682c0"
patches:
"1.1.1":
- patch_file: "patches/0001-fix-spirv-cross-includes-1.1.x.patch"
base_path: "source_subfolder"
155 changes: 155 additions & 0 deletions recipes/moltenvk/all/conanfile.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
from conans import ConanFile, CMake, tools
from conans.errors import ConanInvalidConfiguration
import os


class MoltenVKConan(ConanFile):
name = "moltenvk"
description = "MoltenVK is a Vulkan Portability implementation. It " \
"layers a subset of the high-performance, industry-standard " \
"Vulkan graphics and compute API over Apple's Metal " \
"graphics framework, enabling Vulkan applications to run " \
"on iOS and macOS. "
license = "Apache-2.0"
topics = ("conan", "moltenvk", "khronos", "vulkan", "metal")
homepage = "https://github.com/KhronosGroup/MoltenVK"
url = "https://github.com/conan-io/conan-center-index"

settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"with_spirv_tools": [True, False],
"tools": [True, False]
}
default_options = {
"shared": False,
"fPIC": True,
"with_spirv_tools": True,
"tools": True
}

exports_sources = ["CMakeLists.txt", "patches/**"]
generators = "cmake"
_cmake = None

@property
def _source_subfolder(self):
return "source_subfolder"

def configure(self):
if self.options.shared:
del self.options.fPIC
if self.settings.compiler.get_safe("cppstd"):
tools.check_min_cppstd(self, 11)
if self.settings.os not in ["Macos", "iOS", "tvOS"]:
raise ConanInvalidConfiguration("MoltenVK only supported on MacOS, iOS and tvOS")

def requirements(self):
self.requires("cereal/1.3.0")
self.requires("glslang/8.13.3559")
self.requires("spirv-cross/{}".format(self._spirv_cross_version))
self.requires("vulkan-headers/{}".format(self._vulkan_headers_version))
if self.options.with_spirv_tools:
self.requires("spirv-tools/v2020.5")
if tools.Version(self.version) < "1.1.0":
raise ConanInvalidConfiguration("MoltenVK < 1.1.0 requires vulkan-portability")

@property
def _spirv_cross_version(self):
return {
"1.1.1": "20210115", # can't compile with spirv-cross < 20210115
"1.1.0": "20200917", # works with spirv-cross 20200917 only
}.get(self.version)
SpaceIm marked this conversation as resolved.
Show resolved Hide resolved

@property
def _vulkan_headers_version(self):
return {
"1.1.1": "1.2.162.0",
"1.1.0": "1.2.154.0",
"1.0.44": "1.2.148.0",
"1.0.43": "1.2.141.0",
"1.0.42": "1.2.141.0",
"1.0.41": "1.2.135.0",
"1.0.40": "1.2.131.1",
"1.0.39": "1.1.130.0",
"1.0.38": "1.1.126.0",
Comment on lines +81 to +87
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do we need all these versions if we don't add them to our conandata.yml?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I prefer to keep this for documentation, there are very strict requirements on dependencies versions and I don't want to lose this information.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok, if someone wants an older version, it will be quite easy to add it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actually I've tested all versions from 1.0.39 to 1.1.1, and it works.

"1.0.37": "1.1.121.0",
"1.0.36": "1.1.114.0",
"1.0.35": "1.1.108.0",
"1.0.34": "1.1.106.0",
"1.0.33": "1.1.101.0",
"1.0.32": "1.1.97.0",
"1.0.31": "1.1.97.0",
"1.0.30": "1.1.92.0",
"1.0.29": "1.1.92.0",
"1.0.28": "1.1.92.0",
"1.0.27": "1.1.92.0",
"1.0.26": "1.1.85.0",
"1.0.25": "1.1.85.0",
"1.0.24": "1.1.85.0",
"1.0.23": "1.1.85.0",
"1.0.22": "1.1.82.0",
"1.0.21": "1.1.82.0",
"1.0.20": "1.1.82.0",
"1.0.19": "1.1.82.0",
"1.0.18": "1.1.82.0",
"1.0.17": "1.1.82.0",
}.get(self.version)
SpaceIm marked this conversation as resolved.
Show resolved Hide resolved

def package_id(self):
del self.info.settings.compiler.version
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do not remove the compiler.version. Even if it only works with apple-clang 12, it is needed.

Copy link
Contributor Author

@SpaceIm SpaceIm Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The problem is that MoltenVK > 1.0.41 must be built with XCode >= 12, but can be consumed with XCode < 12...

Is is ok if I set self.info.settings.compiler.version to 12 in package_id() if self.settings.compiler.version < 12?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's the use-case for validate + compatible_packages: we declare that the recipe can only be built with XCode 12, but then in the compatible_packages we list all the versions that can consume it (it will be the same scenario for compiler.cppstd).

It is the idea I tried to ilustrate here (conan-io/examples#73), have a look at the conanfile.py, more or less:

class Recipe(ConanFile):
    def configure(self):
        if self.settings.os not in ["Macos", "iOS", "tvOS"]:
            raise ConanInvalidConfiguration("MoltenVK only supported on MacOS, iOS and tvOS")

    def validate(self):
        if tools.Version(self.settings.compiler.version) < "12":
            raise ConanInvalidConfiguration("MoltenVK {} requires XCode 12 or higher at build time".format(self.version))

    def package_id(self):
        for xcode in ("9", "10", "11"):
            compatible_pkg = self.info.clone()
            compatible_pkg.settings.compiler.version = xcode
            self.compatible_packages.append(compatible_pkg)

The problem with removing compiler.version is that CCI identifies that it is the same package-id for all the macOS builds (9.1, 10, 11, 12), CCI removes duplicates and chooses to build with the oldest of all the compilers that are available. CCI chooses apple-clang 9.1 and then it founds the ConanInvalidConfiguration in the build() method.

Copy link
Contributor Author

@SpaceIm SpaceIm Feb 22, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the explanation about CI logic.

Regarding package_id(), shouldn't it be something like this?

    def package_id(self):
        if tools.Version(self.settings.compiler.version) < "12.0":
            compatible_pkg = self.info.clone()
            compatible_pkg.settings.compiler.version = "12.0"
            self.compatible_packages.append(compatible_pkg)

So I don't fully understand what happen in validate() (and how it interacts with package_id()). It won't raise if compiler version is < 12 and a binary is available? How? I thought that validate() was called even when we don't build.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤕 you are right regarding package_id() implementation.

Conan captures the ConanInvalidConfiguration if it is raised from the validate() method. And will it use in different ways depending on the command. If it conan info, Conan will print that the computed package-ID is invalid instead of raising the error, if it is a conan create/build then it will raise.

Besides the UX, we are preparing for Conan 2.0 where two-profiles would be the default. Still we don't know what is going to happen with the build-requires, if we will expand the full graph always (also the build-requires). If that is the case, when you are installing packages for a host, you really don't care (and probably don't know) the profile used to build them, the recipes in the build context will probably get a default (?) empty (?) profile that will likely raise a ConanInvalidConfiguration.... but we will capture the exception unless you really want to use/build those binaries and Conan needs to retrieve/build the package. This is WIP, probably it will change, but it fits with the better UX experience.


def source(self):
tools.get(**self.conan_data["sources"][self.version])
os.rename("MoltenVK-" + self.version, self._source_subfolder)

def _patch_sources(self):
for patch in self.conan_data.get("patches", {}).get(self.version, []):
tools.patch(**patch)
if tools.Version(self.version) >= "1.1.0":
tools.replace_in_file(os.path.join(self._source_subfolder, "MoltenVK", "MoltenVK", "GPUObjects", "MVKDevice.mm"),
"#include \"mvkGitRevDerived.h\"",
"static const char* mvkRevString = \"{}\";".format(self._mvk_commit_hash))

@property
def _mvk_commit_hash(self):
return {
"1.1.1": "49de6604b0395057e7d3b7ce7001ed29b25708f7",
"1.1.0": "b9b78def172074872bfbb1015ccf75eeec554ae2",
}.get(self.version)

def _configure_cmake(self):
if self._cmake:
return self._cmake
self._cmake = CMake(self)
self._cmake.definitions["MVK_VERSION"] = self.version
self._cmake.definitions["MVK_WITH_SPIRV_TOOLS"] = self.options.with_spirv_tools
self._cmake.definitions["MVK_BUILD_SHADERCONVERTER_TOOL"] = self.options.tools
self._cmake.configure()
return self._cmake

def build(self):
if tools.Version(self.version) >= "1.0.42" and tools.Version(self.settings.compiler.version) < "12":
raise ConanInvalidConfiguration("MoltenVK {} requires XCode 12 or higher at build time".format(self.version))
self._patch_sources()
cmake = self._configure_cmake()
cmake.build()

def package(self):
self.copy("LICENSE", dst="licenses", src=self._source_subfolder)
cmake = self._configure_cmake()
cmake.install()

def package_info(self):
self.cpp_info.libs = ["MoltenVK"]
self.cpp_info.frameworks = ["Metal", "Foundation", "QuartzCore", "AppKit", "IOSurface"]
if self.settings.os == "Macos":
self.cpp_info.frameworks.append("IOKit")
elif self.settings.os in ["iOS", "tvOS"]:
self.cpp_info.frameworks.append("UIKit")

if self.options.tools:
bin_path = os.path.join(self.package_folder, "bin")
self.output.info("Appending PATH environment variable: {}".format(bin_path))
self.env_info.PATH.append(bin_path)
Loading