use std::{
env,
path::{Path, PathBuf},
};
fn static_link_windows(
feat_window: bool,
feat_audio: bool,
feat_graphics: bool,
env: WinEnv,
build_lib_path: &Path,
) {
let arch = match env::var("CARGO_CFG_TARGET_ARCH").as_deref() {
Ok("x86") => "x86",
Ok("x86_64") => "x64",
_ => panic!("Failed to determine cpu arch (CARGO_CFG_TARGET_ARCH))"),
};
let sfml_extlibs_path: PathBuf = format!(
"SFML/extlibs/libs-{seg}/{arch}",
seg = env.sfml_extlib_name()
)
.into();
for lib in ["freetype", "openal32", "vorbisenc", "vorbisfile", "vorbis"] {
let lib_name = env.lib_filename(lib);
let from = sfml_extlibs_path.join(&lib_name);
let to = build_lib_path.join(&lib_name);
let result = std::fs::copy(&from, &to);
if let Err(e) = result {
println!("cargo:warning=Failed to copy {from:?} to {to:?}: {e}",);
}
}
println!("cargo:rustc-link-lib=dylib=winmm");
println!("cargo:rustc-link-lib=dylib=user32");
if feat_window {
println!("cargo:rustc-link-lib=dylib=opengl32");
println!("cargo:rustc-link-lib=dylib=gdi32");
}
if feat_graphics {
println!("cargo:rustc-link-lib=static=freetype");
}
if feat_audio {
println!("cargo:rustc-link-lib=static=openal32");
println!("cargo:rustc-link-lib=static=FLAC");
println!("cargo:rustc-link-lib=static=vorbisenc");
println!("cargo:rustc-link-lib=static=vorbisfile");
println!("cargo:rustc-link-lib=static=vorbis");
println!("cargo:rustc-link-lib=static=ogg");
}
}
fn static_link_linux(feat_window: bool, feat_audio: bool, feat_graphics: bool) {
println!("cargo:rustc-link-lib=dylib=udev");
if feat_window {
println!("cargo:rustc-link-lib=dylib=GL");
println!("cargo:rustc-link-lib=dylib=X11");
println!("cargo:rustc-link-lib=dylib=Xcursor");
println!("cargo:rustc-link-lib=dylib=Xrandr");
}
if feat_graphics {
unix_graphics_link_support_libs();
}
if feat_audio {
pkgconfig_probe_with_fallback("openal", "rustc-link-lib=dylib=openal");
unix_audio_link_support_libs();
}
}
fn pkgconfig_probe_with_fallback(lib: &str, fallback: &str) {
if let Err(e) = pkg_config::probe_library(lib) {
eprintln!("cargo:warning=pkg-config failed: {e}.\nTrying manual link");
println!("cargo:{fallback}");
}
}
fn unix_graphics_link_support_libs() {
pkgconfig_probe_with_fallback("freetype2", "rustc-link-lib=dylib=freetype");
}
fn unix_audio_link_support_libs() {
pkgconfig_probe_with_fallback("vorbisenc", "rustc-link-lib=dylib=vorbisenc");
pkgconfig_probe_with_fallback("vorbisfile", "rustc-link-lib=dylib=vorbisfile");
pkgconfig_probe_with_fallback("vorbis", "rustc-link-lib=dylib=vorbis");
println!("cargo:rustc-link-lib=static=FLAC");
println!("cargo:rustc-link-lib=static=ogg");
}
enum WinEnv {
Gnu,
Msvc,
}
impl WinEnv {
fn get() -> Option<Self> {
match env::var("CARGO_CFG_TARGET_ENV").as_deref() {
Ok("gnu") => Some(Self::Gnu),
Ok("msvc") => Some(Self::Msvc),
_ => None,
}
}
fn sfml_extlib_name(&self) -> &'static str {
match self {
WinEnv::Gnu => "mingw",
WinEnv::Msvc => "msvc",
}
}
fn lib_ext(&self) -> &'static str {
match self {
WinEnv::Gnu => ".a",
WinEnv::Msvc => ".lib",
}
}
fn lib_prefix(&self) -> &'static str {
match self {
WinEnv::Gnu => "lib",
WinEnv::Msvc => "",
}
}
fn lib_filename(&self, lib: &str) -> String {
[self.lib_prefix(), lib, self.lib_ext()].concat()
}
}
fn main() {
println!("cargo:rerun-if-changed=CSFML");
let feat_audio = env::var("CARGO_FEATURE_AUDIO").is_ok();
let feat_window = env::var("CARGO_FEATURE_WINDOW").is_ok();
let feat_graphics = env::var("CARGO_FEATURE_GRAPHICS").is_ok();
let mut cmake = cmake::Config::new("SFML");
let win_env = WinEnv::get();
let release_profile = env::var("PROFILE").is_ok_and(|prof| prof == "release");
cmake.profile("Release");
cmake
.define("CMAKE_FIND_DEBUG_MODE", "TRUE") .define("BUILD_SHARED_LIBS", "FALSE")
.define("SFML_BUILD_NETWORK", "FALSE")
.define("SFML_INSTALL_PKGCONFIG_FILES", "FALSE")
.no_build_target(true);
if !feat_audio {
cmake.define("SFML_BUILD_AUDIO", "FALSE");
} else {
let (libogg_loc, libflac_loc) = match win_env {
Some(WinEnv::Msvc) => {
let libflac_loc = if release_profile {
"/build/src/libFLAC/Release"
} else {
"/build/src/libFLAC/Debug"
};
("/lib", libflac_loc)
}
_ => ("/lib", "/build/src/libFLAC"),
};
match env::var("DEP_FLAC_ROOT") {
Ok(libflac_root) => {
cmake.define(
"CMAKE_PREFIX_PATH",
[&libflac_root, libogg_loc, ";", &libflac_root, libflac_loc].concat(),
);
}
Err(e) => {
println!(
"cargo:warning=Failed to get DEP_FLAC_ROOT: {e}.\n\
Now the build will horribly break.\n\
Except maybe on CI. ;)"
);
}
}
}
if !feat_window {
cmake.define("SFML_BUILD_WINDOW", "FALSE");
}
if !feat_graphics {
cmake.define("SFML_BUILD_GRAPHICS", "FALSE");
}
let cmake_build_path = cmake.build();
let mut build = cc::Build::new();
build
.cpp(true)
.flag_if_supported("--std=c++17")
.define("CSFML_SYSTEM_EXPORTS", None)
.define("CSFML_AUDIO_EXPORTS", None)
.define("CSFML_WINDOW_EXPORTS", None)
.define("CSFML_GRAPHICS_EXPORTS", None)
.define("SFML_STATIC", None)
.include("CSFML/src/")
.include("SFML/include");
build.files(
[
"CSFML/src/System/Clock.cpp",
"CSFML/src/System/Sleep.cpp",
"CSFML/src/System/InputStreamHelper.cpp",
"CSFML/src/System/SfString.cpp",
"CSFML/src/System/SfStdString.cpp",
"CSFML/src/System/SfStdVector.cpp",
]
.iter(),
);
if feat_audio {
build.files(
[
"CSFML/src/Audio/Listener.cpp",
"CSFML/src/Audio/Music.cpp",
"CSFML/src/Audio/Sound.cpp",
"CSFML/src/Audio/SoundBuffer.cpp",
"CSFML/src/Audio/SoundBufferRecorder.cpp",
"CSFML/src/Audio/SoundRecorder.cpp",
"CSFML/src/Audio/CustomSoundRecorder.cpp",
"CSFML/src/Audio/CustomSoundStream.cpp",
]
.iter(),
);
}
if feat_window {
build.files(
[
"CSFML/src/Window/Clipboard.cpp",
"CSFML/src/Window/Cursor.cpp",
"CSFML/src/Window/Joystick.cpp",
"CSFML/src/Window/Keyboard.cpp",
"CSFML/src/Window/Mouse.cpp",
"CSFML/src/Window/Sensor.cpp",
"CSFML/src/Window/Touch.cpp",
"CSFML/src/Window/VideoMode.cpp",
"CSFML/src/Window/Window.cpp",
"CSFML/src/Window/Context.cpp",
]
.iter(),
);
}
if feat_graphics {
build.files(
[
"CSFML/src/Graphics/CircleShape.cpp",
"CSFML/src/Graphics/ConvexShape.cpp",
"CSFML/src/Graphics/Font.cpp",
"CSFML/src/Graphics/Image.cpp",
"CSFML/src/Graphics/RectangleShape.cpp",
"CSFML/src/Graphics/RenderTexture.cpp",
"CSFML/src/Graphics/RenderWindow.cpp",
"CSFML/src/Graphics/Shader.cpp",
"CSFML/src/Graphics/CustomShape.cpp",
"CSFML/src/Graphics/Sprite.cpp",
"CSFML/src/Graphics/Text.cpp",
"CSFML/src/Graphics/Texture.cpp",
"CSFML/src/Graphics/Transform.cpp",
"CSFML/src/Graphics/VertexBuffer.cpp",
"CSFML/src/Graphics/View.cpp",
]
.iter(),
);
}
build.compile("rcsfml");
let is_windows = env::var("CARGO_CFG_WINDOWS").is_ok();
let is_unix = env::var("CARGO_CFG_UNIX").is_ok();
let is_linux = env::var("CARGO_CFG_TARGET_OS")
.map(|os| os == "linux")
.unwrap_or(false);
let is_macos = env::var("CARGO_CFG_TARGET_OS")
.map(|os| os == "macos")
.unwrap_or(false);
if is_macos {
link_mac_os_frameworks();
}
let link_search = if matches!(win_env, Some(WinEnv::Msvc)) {
"build/lib/Release"
} else {
"build/lib"
};
let build_lib_path = cmake_build_path.join(link_search);
println!(
"cargo:rustc-link-search=native={}",
build_lib_path.display()
);
println!("cargo:rustc-link-lib=static=rcsfml");
link_sfml_subsystem("system");
if is_unix && is_linux {
static_link_linux(feat_window, feat_audio, feat_graphics);
} else if is_windows {
match win_env {
Some(env) => {
static_link_windows(feat_window, feat_audio, feat_graphics, env, &build_lib_path);
}
None => {
panic!("Failed to determine windows environment (MSVC/Mingw)");
}
}
} else if is_macos {
if feat_graphics {
unix_graphics_link_support_libs();
}
if feat_audio {
unix_audio_link_support_libs();
}
} else {
panic!("Uhhh... Can't determine your environment. Sorry.");
}
if feat_audio {
link_sfml_subsystem("audio");
}
if feat_window {
link_sfml_subsystem("window");
}
if feat_graphics {
link_sfml_subsystem("graphics");
}
}
fn link_sfml_subsystem(name: &str) {
println!("cargo:rustc-link-lib=static=sfml-{name}-s");
}
fn link_mac_os_frameworks() {
println!("cargo:rustc-link-lib=framework=CoreFoundation");
println!("cargo:rustc-link-lib=framework=CoreGraphics");
println!("cargo:rustc-link-lib=framework=IOKit");
println!("cargo:rustc-link-lib=framework=Carbon");
println!("cargo:rustc-link-lib=framework=AppKit");
println!("cargo:rustc-link-lib=framework=OpenAL");
}