diff --git a/recipes/yojimbo/all/conanfile.py b/recipes/yojimbo/all/conanfile.py index 96de2407727bd..a727c0b4af7a6 100644 --- a/recipes/yojimbo/all/conanfile.py +++ b/recipes/yojimbo/all/conanfile.py @@ -1,117 +1,173 @@ import os -from conans import ConanFile, MSBuild, AutoToolsBuildEnvironment, tools -from conans.errors import ConanInvalidConfiguration +import textwrap +from pathlib import Path + import yaml +from conan import ConanFile +from conan.errors import ConanInvalidConfiguration +from conan.tools.env import VirtualBuildEnv +from conan.tools.files import chdir, collect_libs, copy, get, replace_in_file, rmdir, save +from conan.tools.gnu import Autotools, AutotoolsDeps, AutotoolsToolchain +from conan.tools.layout import basic_layout +from conan.tools.microsoft import MSBuild, MSBuildDeps, MSBuildToolchain, is_msvc +from conan.tools.scm import Version + +required_conan_version = ">=2.0.0" class YojimboConan(ConanFile): name = "yojimbo" - url = "https://github.com/conan-io/conan-center-index" - homepage = "https://github.com/networkprotocol/yojimbo" - topics = ("conan", "yojimbo", "game", "udp", "protocol", "client-server", "multiplayer-game-server") description = "A network library for client/server games written in C++" license = "BSD-3-Clause" - exports = "submoduledata.yml" - build_requires = "premake/5.0.0-alpha15" - settings = "os", "arch", "compiler", "build_type" - options = {"fPIC": [True, False]} - default_options = {"fPIC": True} + url = "https://github.com/conan-io/conan-center-index" + homepage = "https://github.com/networkprotocol/yojimbo" + topics = ("game", "udp", "protocol", "client-server", "multiplayer-game-server") - _source_subfolder = "source_subfolder" - _build_subfolder = "build_subfolder" + package_type = "static-library" + settings = "os", "arch", "compiler", "build_type" + options = { + "fPIC": [True, False], + } + default_options = { + "fPIC": True, + } - def configure(self): - if self.settings.arch != "x86_64": - raise ConanInvalidConfiguration("Only 64-bit architecture supported") + def export_sources(self): + copy(self, "submoduledata.yml", src=self.recipe_folder, dst=self.export_sources_folder) def config_options(self): if self.settings.os == "Windows": del self.options.fPIC - def requirements(self): - self.requires("libsodium/1.0.18") - self.requires("mbedtls/2.25.0") - - def source(self): - tools.get(**self.conan_data["sources"][self.version], strip_root=True, destination=self._source_subfolder) - - submodule_filename = os.path.join(self.recipe_folder, 'submoduledata.yml') - with open(submodule_filename, 'r') as submodule_stream: - submodules_data = yaml.load(submodule_stream) - for path, submodule in submodules_data["submodules"][self.version].items(): - submodule_data = { - "url": submodule["url"], - "sha256": submodule["sha256"], - "destination": os.path.join(self._source_subfolder, submodule["destination"]), - "strip_root": True - } - - tools.get(**submodule_data) - submodule_source = os.path.join(self._source_subfolder, path) - tools.rmdir(submodule_source) - - def build(self): + def layout(self): + basic_layout(self, src_folder="src") - # Before building we need to make some edits to the premake file to build using conan dependencies rather than local/bundled + def requirements(self): + self.requires("libsodium/1.0.19") + self.requires("mbedtls/2.28.4") # v3+ is not supported - # Generate the list of dependency include and library paths as strings - include_path_str = ', '.join('"{0}"'.format(p) for p in self.deps_cpp_info["libsodium"].include_paths + self.deps_cpp_info["mbedtls"].include_paths) - lib_path_str = ', '.join('"{0}"'.format(p) for p in self.deps_cpp_info["libsodium"].lib_paths + self.deps_cpp_info["mbedtls"].lib_paths) + def validate_build(self): + if self.settings_build.build_type == "Debug": + if self.settings_build.os != "Windows" and self.settings_build.compiler == "gcc" and Version(self.settings_build.compiler.version) < 8: + raise ConanInvalidConfiguration("Debug build requires GCC >= 8 due to util-linux-libuuid") - premake_path = os.path.join(self._source_subfolder, "premake5.lua") + def build_requirements(self): + self.tool_requires("premake/5.0.0-alpha15") - if self.settings.os == "Windows": - - # Replace Windows directory seperator - include_path_str = include_path_str.replace("\\", "/") - lib_path_str = lib_path_str.replace("\\", "/") - - # Edit the premake script to use conan rather than bundled dependencies - tools.replace_in_file(premake_path, "includedirs { \".\", \"./windows\"", "includedirs { \".\", %s" % include_path_str, strict=True) - tools.replace_in_file(premake_path, "libdirs { \"./windows\" }", "libdirs { %s }" % lib_path_str, strict=True) - - # Edit the premake script to change the name of libsodium - tools.replace_in_file(premake_path, "\"sodium\"", "\"libsodium\"", strict=True) - + def source(self): + get(self, **self.conan_data["sources"][self.version], strip_root=True) + + submodule_filename = os.path.join(self.export_sources_folder, "submoduledata.yml") + with open(submodule_filename, "r", encoding="utf8") as submodule_stream: + submodules_data = yaml.load(submodule_stream, Loader=yaml.SafeLoader) + for path, submodule_data in submodules_data["submodules"][self.version].items(): + get(self, **submodule_data, strip_root=True) + submodule_source = os.path.join(self.source_folder, path) + rmdir(self, submodule_source) + + @property + def _conan_paths_lua(self): + return os.path.join(self.generators_folder, "conan_paths.lua") + + def generate(self): + venv = VirtualBuildEnv(self) + venv.generate() + if is_msvc(self): + tc = MSBuildToolchain(self) + tc.generate() + tc = MSBuildDeps(self) + tc.generate() else: - - # Edit the premake script to use conan rather than local dependencies - tools.replace_in_file(premake_path, "\"/usr/local/include\"", include_path_str, strict=True) - - - # Build using premake - - if self.settings.compiler == "Visual Studio": - generator = "vs" + {"16": "2019", - "15": "2017", - "14": "2015", - "12": "2013", - "11": "2012", - "10": "2010", - "9": "2008", - "8": "2005"}.get(str(self.settings.compiler.version)) + tc = AutotoolsToolchain(self) + tc.generate() + tc = AutotoolsDeps(self) + tc.generate() + + deps = list(reversed(self.dependencies.host.topological_sort.values())) + includedirs = ', '.join(f'"{p}"'.replace("\\", "/") for dep in deps for p in dep.cpp_info.aggregated_components().includedirs) + libdirs = ', '.join(f'"{p}"'.replace("\\", "/") for dep in deps for p in dep.cpp_info.aggregated_components().libdirs) + save(self, self._conan_paths_lua, + "conan_includedirs = {" + includedirs + "}\n" + "conan_libdirs = {" + libdirs + "}\n") + + def _patch_sources(self): + premake_path = os.path.join(self.source_folder, "premake5.lua") + replace_in_file(self, premake_path, ', "/usr/local/include"', "") + if self.settings.os == "Windows": + replace_in_file(self, premake_path, '"sodium"', '"libsodium"') + + # Inject Conan dependencies + conan_paths_lua = self._conan_paths_lua.replace("\\", "/") + save(self, premake_path, + f"\ndofile('{conan_paths_lua}')\n" + + textwrap.dedent(""" + workspace "Yojimbo" + configurations { "Debug", "Release" } + includedirs { conan_includedirs } + libdirs { conan_libdirs } + """), append=True) + + @property + def _premake_generator(self): + if is_msvc(self): + generator = "vs2015" else: generator = "gmake2" + return generator + + def _inject_msbuild_toolchain(self): + vcxproj_files = list(self.source_path.rglob("*.vcxproj")) + platform_toolset = MSBuildToolchain(self).toolset + import_conan_generators = "" + for props_file in ["conantoolchain.props", "conandeps.props"]: + props_path = os.path.join(self.generators_folder, props_file) + if os.path.exists(props_path): + import_conan_generators += f"" + for vcxproj_file in vcxproj_files: + replace_in_file(self, vcxproj_file, "v140", platform_toolset) + if props_path: + replace_in_file( + self, vcxproj_file, + r'', + rf'{import_conan_generators}', + ) - with tools.chdir(self._source_subfolder): - self.run("premake5 %s" % generator) - - if self.settings.compiler == "Visual Studio": + def build(self): + self._patch_sources() + # Build using premake + with chdir(self, self.source_folder): + self.run(f"premake5 {self._premake_generator}") + if is_msvc(self): + self._inject_msbuild_toolchain() msbuild = MSBuild(self) msbuild.build("Yojimbo.sln") else: + # Remove incorrect arch flags + for make_file in Path(self.source_folder).rglob("*.make"): + if self.settings.arch not in ["x86", "x86_64"]: + replace_in_file(self, make_file, "-msse2", "", strict=False) + if self.settings.arch != "x86_64": + replace_in_file(self, make_file, "-m64", "", strict=False) config = "debug" if self.settings.build_type == "Debug" else "release" config += "_x64" - env_build = AutoToolsBuildEnvironment(self) - env_build.make(args=["config=%s" % config]) - + autotools = Autotools(self) + autotools.make(args=[f"config={config}"]) def package(self): - self.copy(pattern="LICENCE", dst="licenses", src=self._source_subfolder) - self.copy(pattern="yojimbo.h", dst="include", src=self._source_subfolder) - - self.copy(pattern="*/yojimbo.lib", dst="lib", keep_path=False) - self.copy(pattern="*/libyojimbo.a", dst="lib", keep_path=False) + copy(self, "LICENCE", + dst=os.path.join(self.package_folder, "licenses"), + src=self.source_folder) + copy(self, "yojimbo.h", + dst=os.path.join(self.package_folder, "include"), + src=self.source_folder) + copy(self, "*/yojimbo.lib", + dst=os.path.join(self.package_folder, "lib"), + src=self.source_folder, + keep_path=False) + copy(self, "*/libyojimbo.a", + dst=os.path.join(self.package_folder, "lib"), + src=self.source_folder, + keep_path=False) def package_info(self): - self.cpp_info.libs = tools.collect_libs(self) + self.cpp_info.libs = collect_libs(self) diff --git a/recipes/yojimbo/all/test_package/CMakeLists.txt b/recipes/yojimbo/all/test_package/CMakeLists.txt index 04e93484921eb..51b30ace87e86 100644 --- a/recipes/yojimbo/all/test_package/CMakeLists.txt +++ b/recipes/yojimbo/all/test_package/CMakeLists.txt @@ -1,8 +1,7 @@ -cmake_minimum_required(VERSION 3.1.0) -project(test_package) +cmake_minimum_required(VERSION 3.15) +project(test_package LANGUAGES CXX) -include(${CMAKE_BINARY_DIR}/conanbuildinfo.cmake) -conan_basic_setup() +find_package(yojimbo REQUIRED CONFIG) add_executable(${PROJECT_NAME} test_package.cpp) -target_link_libraries(${PROJECT_NAME} ${CONAN_LIBS}) +target_link_libraries(${PROJECT_NAME} PRIVATE yojimbo::yojimbo) diff --git a/recipes/yojimbo/all/test_package/conanfile.py b/recipes/yojimbo/all/test_package/conanfile.py index bd7165a553cf4..ef5d7042163ec 100644 --- a/recipes/yojimbo/all/test_package/conanfile.py +++ b/recipes/yojimbo/all/test_package/conanfile.py @@ -1,10 +1,19 @@ -from conans import ConanFile, CMake, tools +from conan import ConanFile +from conan.tools.build import can_run +from conan.tools.cmake import cmake_layout, CMake import os class TestPackageConan(ConanFile): - settings = "os", "compiler", "build_type", "arch" - generators = "cmake" + settings = "os", "arch", "compiler", "build_type" + generators = "CMakeDeps", "CMakeToolchain", "VirtualRunEnv" + test_type = "explicit" + + def requirements(self): + self.requires(self.tested_reference_str) + + def layout(self): + cmake_layout(self) def build(self): cmake = CMake(self) @@ -12,6 +21,6 @@ def build(self): cmake.build() def test(self): - if not tools.cross_building(self.settings): - bin_path = os.path.join("bin", "test_package") - self.run(bin_path, run_environment=True) + if can_run(self): + bin_path = os.path.join(self.cpp.build.bindir, "test_package") + self.run(bin_path, env="conanrun") diff --git a/recipes/yojimbo/all/test_package/test_package.cpp b/recipes/yojimbo/all/test_package/test_package.cpp index c2571a92dbdc9..634213bbf1d4a 100644 --- a/recipes/yojimbo/all/test_package/test_package.cpp +++ b/recipes/yojimbo/all/test_package/test_package.cpp @@ -10,10 +10,10 @@ int main() std::cout << "Failed to initialize Yojimbo!\n"; return 1; } - + std::cout << "Succesfully initialized Yojimbo\n"; - + ShutdownYojimbo(); - + return 0; }