infinipaint/conan/sdl/all/conanfile.py
2026-04-12 17:31:32 +03:00

438 lines
21 KiB
Python

from conan import ConanFile
from conan.errors import ConanInvalidConfiguration
from conan.tools.apple import is_apple_os
from conan.tools.files import (
get, replace_in_file, rm, rmdir, copy,
apply_conandata_patches, export_conandata_patches
)
from conan.tools.microsoft import is_msvc
from conan.tools.scm import Version
from conan.tools.cmake import CMake, CMakeToolchain, cmake_layout
from conan.tools.env import Environment
import os
required_conan_version = ">=2.1"
class SDLConan(ConanFile):
name = "sdl"
description = "Access to audio, keyboard, mouse, joystick, and graphics hardware via OpenGL, Direct3D and Vulkan"
license = "Zlib"
url = "https://github.com/conan-io/conan-center-index"
homepage = "https://www.libsdl.org"
topics = ("sdl2", "audio", "keyboard", "graphics", "opengl")
package_type = "library"
settings = "os", "arch", "compiler", "build_type"
options = {
"shared": [True, False],
"fPIC": [True, False],
"directx": [True, False],
"alsa": [True, False],
"jack": [True, False],
"pulse": [True, False],
"sndio": [True, False],
"nas": [True, False],
"esd": [True, False],
"arts": [True, False],
"x11": [True, False],
"xcursor": [True, False],
"xinerama": [True, False],
"xinput": [True, False],
"xrandr": [True, False],
"xscrnsaver": [True, False],
"xshape": [True, False],
"xvm": [True, False],
"wayland": [True, False],
"directfb": [True, False],
"iconv": [True, False],
"video_rpi": [True, False],
"sdl2main": [True, False],
"opengl": [True, False],
"opengles": [True, False],
"vulkan": [True, False],
"libunwind": [True, False],
"hidapi": [True, False],
}
default_options = {
"shared": False,
"fPIC": True,
"directx": True,
"alsa": True,
"jack": False,
"pulse": True,
"sndio": False,
"nas": False,
"esd": False,
"arts": False,
"x11": True,
"xcursor": True,
"xinerama": True,
"xinput": True,
"xrandr": True,
"xscrnsaver": True,
"xshape": True,
"xvm": True,
"wayland": True,
"directfb": False,
"video_rpi": False,
"sdl2main": True,
"opengl": True,
"opengles": True,
"vulkan": True,
"libunwind": True,
"hidapi": True,
}
generators = "CMakeDeps", "PkgConfigDeps", "VirtualBuildEnv"
@property
def _is_clang_cl(self):
return self.settings.os == "Windows" and self.settings.compiler == "clang" and \
self.settings.compiler.get_safe("runtime")
def layout(self):
cmake_layout(self, src_folder="src")
def export_sources(self):
export_conandata_patches(self)
def generate(self):
self.define_toolchain()
lib_paths = [lib for _, dep in self.dependencies.items() for lib in dep.cpp_info.libdirs]
env = Environment()
env.define_path("LIBRARY_PATH", os.pathsep.join(lib_paths))
env = env.vars(self, scope="build")
env.save_script("sdl_env")
def config_options(self):
# Don't depend on iconv on Apple by default
# SDL2 depends on many system freamworks,
# which depend on the system-provided iconv
# and can conflict with the Conan provided one
self.options.iconv = not is_apple_os(self)
if self.settings.os == "Windows":
del self.options.fPIC
if (is_msvc(self) or self._is_clang_cl):
del self.options.iconv
if self.settings.os != "Linux":
del self.options.alsa
del self.options.jack
del self.options.pulse
del self.options.sndio
del self.options.nas
del self.options.esd
del self.options.arts
del self.options.x11
del self.options.xcursor
del self.options.xinerama
del self.options.xinput
del self.options.xrandr
del self.options.xscrnsaver
del self.options.xshape
del self.options.xvm
del self.options.wayland
del self.options.directfb
del self.options.video_rpi
del self.options.libunwind
if self.settings.os != "Windows":
del self.options.directx
def configure(self):
if self.options.shared:
self.options.rm_safe("fPIC")
# TODO: C++ is also required for WinRT and Haiku
if not (self.settings.os == "Android" and self.options.hidapi):
self.settings.rm_safe("compiler.libcxx")
self.settings.rm_safe("compiler.cppstd")
def requirements(self):
if self.options.get_safe("iconv", False):
self.requires("libiconv/1.17")
if self.settings.os == "Linux":
if self.options.alsa:
self.requires("libalsa/1.2.10")
if self.options.pulse:
self.requires("pulseaudio/14.2")
if self.options.opengl:
self.requires("opengl/system")
if self.options.nas:
self.requires("nas/1.9.5")
if self.options.wayland:
self.requires("wayland/1.22.0")
self.requires("xkbcommon/1.6.0")
self.requires("egl/system")
if self.options.libunwind:
self.requires("libunwind/1.8.0")
def validate(self):
# SDL>=2.0.18 requires xcode 12 or higher because it uses CoreHaptics.
if is_apple_os(self) and Version(self.settings.compiler.version) < "12":
raise ConanInvalidConfiguration("{}/{} requires xcode 12 or higher".format(self.name, self.version))
if self.settings.os == "Linux":
if self.options.sndio:
raise ConanInvalidConfiguration("Package for 'sndio' is not available (yet)")
if self.options.jack:
raise ConanInvalidConfiguration("Package for 'jack' is not available (yet)")
if self.options.esd:
raise ConanInvalidConfiguration("Package for 'esd' is not available (yet)")
if self.options.directfb:
raise ConanInvalidConfiguration("Package for 'directfb' is not available (yet)")
def build_requirements(self):
self.tool_requires("cmake/[>3.27 <4]")
if self.settings.os == "Linux" and not self.conf.get("tools.gnu:pkg_config", check_type=str):
self.tool_requires("pkgconf/2.1.0")
if hasattr(self, "settings_build") and self.options.get_safe("wayland"):
self.build_requires("wayland/1.22.0") # Provides wayland-scanner
def source(self):
get(self, **self.conan_data["sources"][self.version], strip_root=True)
apply_conandata_patches(self)
def _patch_sources(self):
# Ensure to find wayland-scanner from wayland recipe in build requirements (or requirements if 1 profile)
if self.options.get_safe("wayland"):
replace_in_file(self,
os.path.join(self.source_folder, "cmake", "sdlchecks.cmake"),
"find_program(WAYLAND_SCANNER NAMES wayland-scanner REQUIRED)",
'find_program(WAYLAND_SCANNER NAMES wayland-scanner REQUIRED PATHS "${WAYLAND_BIN_DIR}" NO_DEFAULT_PATH)',
)
if not self.options.shared:
replace_in_file(self, os.path.join(self.source_folder, "CMakeLists.txt"), "list(APPEND targets SDL2-static)", "set(targets SDL2-static)")
def define_toolchain(self):
tc = CMakeToolchain(self)
if self.settings.os == "Linux" and self.settings.compiler == "gcc" and Version(self.settings.compiler.version) < 5.0:
tc.preprocessor_definitions["GBM_BO_USE_CURSOR"] = 2
tc.variables["SDL2_DISABLE_INSTALL"] = False # SDL2_* options will get renamed to SDL_ options in the next SDL release
if is_apple_os(self):
tc.variables["CMAKE_OSX_ARCHITECTURES"] = {
"armv8": "arm64",
}.get(str(self.settings.arch), str(self.settings.arch))
cmake_required_includes = [] # List of directories used by CheckIncludeFile (https://cmake.org/cmake/help/latest/module/CheckIncludeFile.html)
cmake_extra_ldflags = []
cmake_extra_libs = []
if self.settings.os != "Windows" and not self.options.shared:
tc.variables["SDL_STATIC_PIC"] = self.options.fPIC
if (is_msvc(self) or self._is_clang_cl) and not self.options.shared:
tc.variables["HAVE_LIBC"] = True
tc.variables["SDL_SHARED"] = self.options.shared
tc.variables["SDL_STATIC"] = not self.options.shared
tc.variables["SDL_TEST"] = False
tc.variables["SDL_OPENGL"] = self.options.opengl
tc.variables["SDL_OPENGLES"] = self.options.opengles
tc.variables["SDL_VULKAN"] = self.options.vulkan
tc.variables["SDL_HIDAPI"] = self.options.hidapi
if self.settings.os == "Linux":
# See https://github.com/bincrafters/community/issues/696
tc.variables["SDL_VIDEO_DRIVER_X11_SUPPORTS_GENERIC_EVENTS"] = 1
tc.variables["SDL_ALSA"] = self.options.alsa
if self.options.alsa:
tc.variables["SDL_ALSA_SHARED"] = self.dependencies["libalsa"].options.shared
tc.variables["HAVE_ASOUNDLIB_H"] = True
tc.variables["HAVE_LIBASOUND"] = True
tc.variables["SDL_JACK"] = self.options.jack
if self.options.jack:
tc.variables["SDL_JACK_SHARED"] = self.options["jack"].shared
tc.variables["SDL_ESD"] = self.options.esd
if self.options.esd:
tc.variables["SDL_ESD_SHARED"] = self.options["esd"].shared
tc.variables["SDL_PULSEAUDIO"] = self.options.pulse
if self.options.pulse:
tc.variables["SDL_PULSEAUDIO_SHARED"] = self.dependencies["pulseaudio"].options.shared
for component in self.dependencies["pulseaudio"].cpp_info.components:
if self.dependencies["pulseaudio"].cpp_info.components[component].libs:
cmake_extra_libs += self.dependencies["pulseaudio"].cpp_info.components[component].libs
cmake_extra_ldflags += ["-L{}".format(it) for it in self.dependencies["pulseaudio"].cpp_info.components[component].libdirs]
cmake_extra_ldflags += ["-lxcb", "-lrt"] # FIXME: SDL sources doesn't take into account transitive dependencies
tc.variables["SDL_SNDIO"] = self.options.sndio
if self.options.sndio:
tc.variables["SDL_SNDIO_SHARED"] = self.options["sndio"].shared
tc.variables["SDL_NAS"] = self.options.nas
if self.options.nas:
cmake_extra_ldflags += ["-lXau"] # FIXME: SDL sources doesn't take into account transitive dependencies
cmake_required_includes += self.dependencies["nas"].cpp_info.includedirs
tc.variables["SDL_NAS_SHARED"] = self.dependencies["nas"].options.shared
tc.variables["SDL_X11"] = self.options.x11
if self.options.x11:
tc.variables["HAVE_XEXT_H"] = True
tc.variables["SDL_X11_XCURSOR"] = self.options.xcursor
if self.options.xcursor:
tc.variables["HAVE_XCURSOR_H"] = True
tc.variables["SDL_X11_XINERAMA"] = self.options.xinerama
if self.options.xinerama:
tc.variables["HAVE_XINERAMA_H"] = True
tc.variables["SDL_X11_XINPUT"] = self.options.xinput
if self.options.xinput:
tc.variables["HAVE_XINPUT_H"] = True
tc.variables["SDL_X11_XRANDR"] = self.options.xrandr
if self.options.xrandr:
tc.variables["HAVE_XRANDR_H"] = True
tc.variables["SDL_X11_XSCRNSAVER"] = self.options.xscrnsaver
if self.options.xscrnsaver:
tc.variables["HAVE_XSS_H"] = True
tc.variables["SDL_X11_XSHAPE"] = self.options.xshape
if self.options.xshape:
tc.variables["HAVE_XSHAPE_H"] = True
tc.variables["SDL_X11_XVM"] = self.options.xvm
if self.options.xvm:
tc.variables["HAVE_XF86VM_H"] = True
tc.variables["SDL_WAYLAND"] = self.options.wayland
if self.options.wayland:
# FIXME: Otherwise 2.0.16 links with system wayland (from egl/system requirement)
cmake_extra_ldflags += ["-L{}".format(it) for it in self.dependencies["wayland"].cpp_info.libdirs]
tc.variables["SDL_WAYLAND_SHARED"] = self.dependencies["wayland"].options.shared
wayland = self.dependencies["wayland"] if not hasattr(self, "settings_build") else self.dependencies.build["wayland"]
wayland_bin_dir = wayland.cpp_info.bindirs[0] # for wayland scanner
tc.variables["WAYLAND_BIN_DIR"] = wayland_bin_dir
tc.variables["SDL_DIRECTFB"] = self.options.directfb
tc.variables["SDL_RPI"] = self.options.video_rpi
tc.variables["HAVE_LIBUNWIND_H"] = self.options.libunwind
elif self.settings.os == "Windows":
tc.variables["SDL_DIRECTX"] = self.options.directx
tc.variables["SDL2_DISABLE_SDL2MAIN"] = not self.options.sdl2main
tc.variables["SDL_LIBICONV"] = self.options.get_safe("iconv", False)
tc.variables["SDL_SYSTEM_ICONV"] = False
# Add extra information collected from the deps
tc.variables["EXTRA_LDFLAGS"] = ";".join(cmake_extra_ldflags)
tc.variables["CMAKE_REQUIRED_INCLUDES"] = ";".join(cmake_required_includes)
cmake_extra_cflags = ["-I{}".format(path) for _, dep in self.dependencies.items() for path in dep.cpp_info.includedirs]
tc.variables["EXTRA_CFLAGS"] = ";".join(cmake_extra_cflags).replace(os.sep, '/')
tc.variables["EXTRA_LIBS"] = ";".join(cmake_extra_libs)
tc.cache_variables["CMAKE_POLICY_DEFAULT_CMP0077"] = "NEW"
tc.generate()
def build(self):
self._patch_sources()
cmake = CMake(self)
cmake.configure()
cmake.build()
def package(self):
cmake = CMake(self)
cmake.install()
copy(self, pattern="LICENSE.txt", src=os.path.join(self.source_folder), dst=os.path.join(self.package_folder, "licenses"))
rm(self, "sdl2-config", os.path.join(self.package_folder, "bin"))
rm(self, "*.pdb", os.path.join(self.package_folder, "lib"))
rm(self, "*.pdb", os.path.join(self.package_folder, "bin"))
rmdir(self, os.path.join(self.package_folder, "cmake"))
rmdir(self, os.path.join(self.package_folder, "lib", "cmake"))
rmdir(self, os.path.join(self.package_folder, "lib", "pkgconfig"))
rmdir(self, os.path.join(self.package_folder, "libdata"))
rmdir(self, os.path.join(self.package_folder, "share"))
if self.settings.os == "Android":
copy(self, pattern="*",
src=os.path.join(self.source_folder, "android-project", "app", "src", "main", "java"),
dst=os.path.join(self.package_folder, "share", "java", "SDL2"))
def package_info(self):
self.cpp_info.set_property("cmake_file_name", "SDL2")
postfix = "d" if self.settings.os != "Android" and self.settings.build_type == "Debug" else ""
# SDL2
lib_postfix = postfix
if (is_msvc(self) or self._is_clang_cl) and not self.options.shared:
lib_postfix = "-static" + postfix
self.cpp_info.components["libsdl2"].set_property("cmake_target_name", "SDL2::SDL2")
if not self.options.shared:
self.cpp_info.components["libsdl2"].set_property("cmake_target_aliases", ["SDL2::SDL2-static"])
self.cpp_info.components["libsdl2"].set_property("pkg_config_name", "sdl2")
self.cpp_info.components["libsdl2"].includedirs.append(os.path.join("include", "SDL2"))
self.cpp_info.components["libsdl2"].libs = ["SDL2" + lib_postfix]
if self.options.get_safe("iconv", False):
self.cpp_info.components["libsdl2"].requires.append("libiconv::libiconv")
if self.settings.os == "Linux":
self.cpp_info.components["libsdl2"].system_libs = ["dl", "rt", "pthread"]
if self.options.alsa:
self.cpp_info.components["libsdl2"].requires.append("libalsa::libalsa")
if self.options.pulse:
self.cpp_info.components["libsdl2"].requires.append("pulseaudio::pulseaudio")
if self.options.opengl:
self.cpp_info.components["libsdl2"].requires.append("opengl::opengl")
if self.options.jack:
self.cpp_info.components["libsdl2"].requires.append("jack::jack")
if self.options.sndio:
self.cpp_info.components["libsdl2"].requires.append("sndio::sndio")
if self.options.nas:
self.cpp_info.components["libsdl2"].requires.append("nas::nas")
if self.options.esd:
self.cpp_info.components["libsdl2"].requires.append("esd::esd")
if self.options.directfb:
self.cpp_info.components["libsdl2"].requires.append("directfb::directfb")
if self.options.video_rpi:
self.cpp_info.components["libsdl2"].libs.append("bcm_host")
self.cpp_info.components["libsdl2"].includedirs.extend([
"/opt/vc/include",
"/opt/vc/include/interface/vcos/pthreads",
"/opt/vc/include/interface/vmcs_host/linux"
])
self.cpp_info.components["libsdl2"].libdirs.append("/opt/vc/lib")
self.cpp_info.components["libsdl2"].sharedlinkflags.append("-Wl,-rpath,/opt/vc/lib")
self.cpp_info.components["libsdl2"].exelinkflags.append("-Wl,-rpath,/opt/vc/lib")
if self.options.wayland:
self.cpp_info.components["libsdl2"].requires.append("wayland::wayland")
self.cpp_info.components["libsdl2"].requires.append("xkbcommon::xkbcommon")
self.cpp_info.components["libsdl2"].requires.append("egl::egl")
if self.options.libunwind:
self.cpp_info.components["libsdl2"].requires.append("libunwind::libunwind")
elif is_apple_os(self) and not self.options.shared:
self.cpp_info.components["libsdl2"].frameworks = [
"CoreVideo", "CoreAudio", "AudioToolbox",
"AVFoundation", "Foundation", "QuartzCore",
]
if self.settings.os == "Macos":
self.cpp_info.components["libsdl2"].frameworks.extend([
"Cocoa",
"Carbon",
"IOKit",
"ForceFeedback",
"CoreFoundation",
"CoreServices",
"AppKit"
])
self.cpp_info.components["libsdl2"].frameworks.append("GameController")
elif self.settings.os in ["iOS", "tvOS", "watchOS"]:
self.cpp_info.components["libsdl2"].frameworks.extend([
"UIKit", "OpenGLES", "GameController", "CoreMotion",
"CoreGraphics", "CoreBluetooth",
])
self.cpp_info.components["libsdl2"].frameworks.append("Metal")
self.cpp_info.components["libsdl2"].sharedlinkflags.append("-Wl,-weak_framework,CoreHaptics")
self.cpp_info.components["libsdl2"].exelinkflags.append("-Wl,-weak_framework,CoreHaptics")
elif self.settings.os == "Windows":
self.cpp_info.components["libsdl2"].system_libs = ["user32", "gdi32", "winmm", "imm32", "ole32", "oleaut32", "version", "uuid", "advapi32", "setupapi", "shell32"]
if self.settings.compiler == "gcc":
self.cpp_info.components["libsdl2"].system_libs.append("mingw32")
elif self.settings.os == "Android" and not self.options.shared:
self.cpp_info.components["libsdl2"].system_libs.extend(["android", "dl", "log"])
if self.options.opengles:
self.cpp_info.components["libsdl2"].system_libs.extend(["GLESv1_CM", "GLESv2"])
self.cpp_info.components["libsdl2"].system_libs.append("OpenSLES")
# SDL2main
if self.options.sdl2main:
self.cpp_info.components["sdl2main"].set_property("cmake_target_name", "SDL2::SDL2main")
self.cpp_info.components["sdl2main"].libs = ["SDL2main" + postfix]
self.cpp_info.components["sdl2main"].requires = ["libsdl2"]
# Workaround to avoid unwanted sdl::sdl target in CMakeDeps generator
self.cpp_info.set_property(
"cmake_target_name",
"SDL2::{}".format("SDL2main" if self.options.sdl2main else "SDL2"),
)