tools/config/configure.R

# Prepare your package for installation here.
# Use 'define()' to define configuration variables.
# Use 'configure_file()' to substitute configuration values.

# Common: Find C/C++ compilers, deal with ccache, find the architecture
# and find CMake.
is_windows = identical(.Platform$OS.type, "windows")
is_macos = identical(Sys.info()[['sysname']], "Darwin")

TARGET_ARCH = Sys.info()[["machine"]]
PACKAGE_BASE_DIR = normalizePath(getwd(), winslash = "/")

syswhich_cmake = Sys.which("cmake")

if (syswhich_cmake != "") {
	CMAKE = normalizePath(syswhich_cmake, winslash = "/")
} else {
	if (is_macos) {
		cmake_found_in_app_folder = file.exists(
			"/Applications/CMake.app/Contents/bin/cmake"
		)
		if (cmake_found_in_app_folder) {
			CMAKE = normalizePath("/Applications/CMake.app/Contents/bin/cmake")
		} else {
			stop("CMake not found during configuration.")
		}
	} else {
		stop("CMake not found during configuration.")
	}
}

# Now, library specific below

# Use pkg-config (if available) to find a system library
package_name = "libImath"
static_library_name = "libImath-3_2"

package_version = "3.1.9"
lib_system = ""

pkgconfig_path = Sys.which("pkg-config")

lib_exists = FALSE
LIB_INCLUDE_ASSIGN = ""
LIB_LINK_ASSIGN = ""

if (nzchar(pkgconfig_path)) {
	pc_status = system2(
		pkgconfig_path,
		c("--exists", sprintf("'%s >= %s'", package_name, package_version)),
		stdout = FALSE,
		stderr = FALSE
	)

	lib_exists = pc_status == 0

	if (lib_exists) {
		message(
			sprintf(
				"*** configure: system %s exists, using that for building the library",
				static_library_name
			)
		)
		quote_paths = function(pkgconfig_output, prefix = "-I") {
			include_dirs = strsplit(
				trimws(gsub(prefix, "", pkgconfig_output, fixed = TRUE)),
				"\\s+"
			)[[1]]

			if (length(include_dirs) == 0) {
				return("")
			}
			if (length(include_dirs) == 1 && include_dirs == "") {
				return("")
			}

			return(
				paste(
					paste0(
						prefix,
						vapply(
							include_dirs,
							shQuote,
							"character"
						)
					),
					collapse = " "
				)
			)
		}

		lib_include = quote_paths(
			system2(
				pkgconfig_path,
				c("--cflags", package_name),
				stdout = TRUE
			),
			prefix = "-I"
		)

		message(
			sprintf("*** configure: using include path '%s'", lib_include)
		)

		lib_link = quote_paths(
			system2(
				pkgconfig_path,
				c("--libs-only-L", package_name),
				stdout = TRUE
			),
			prefix = "-L"
		)

		message(
			sprintf(
				"*** configure: using link path '%s'",
				lib_link
			)
		)
		if (nzchar(lib_include)) {
			LIB_INCLUDE_ASSIGN = sprintf('LIB_INCLUDE = %s', lib_include) #This should already have -I
		}
		if (nzchar(lib_link)) {
			LIB_LINK_ASSIGN = sprintf('LIB_LINK = %s', lib_link) #This should already have -L
		}
	} else {
		message(sprintf("*** %s not found by pkg-config", package_name))
	}
} else {
	message("*** pkg-config not available, skipping to common locations")
}


if (!lib_exists) {
	fallback_prefixes = c(
		"/opt/R/arm64",
		"/opt/R/x86_64",
		"/opt/homebrew",
		"/usr/local",
		"/usr"
	)

	for (prefix in fallback_prefixes) {
		lib_exists_check = file.exists(file.path(
			prefix,
			"lib",
			sprintf("%s.a", static_library_name)
		))
		header_exists = dir.exists(file.path(prefix, "include", "Imath"))

		if (lib_exists_check && header_exists) {
			lib_exists = TRUE
			lib_link = file.path(
				prefix,
				"lib"
			)
			lib_include = file.path(
				prefix,
				"include"
			)
			if (nzchar(lib_include)) {
				LIB_INCLUDE_ASSIGN = sprintf(
					'LIB_INCLUDE = -I"%s"',
					lib_include
				) #This doesn't have -I yet
			}
			if (nzchar(lib_link)) {
				LIB_LINK_ASSIGN = sprintf('LIB_LINK = -L"%s"', lib_link) #This doesn't have -L yet
			}
			break
		}
	}
}


if (lib_exists) {
	lib_dir = substr(strsplit(lib_link, " ")[[1]][1], 3, 500)
	message(
		sprintf(
			"*** configure.R: Found installed version of %s with correct version at '%s', will link in that version to the package.",
			package_name,
			lib_dir
		)
	)
}

define(
	PACKAGE_BASE_DIR = PACKAGE_BASE_DIR,
	TARGET_ARCH = TARGET_ARCH,
	CMAKE = CMAKE,
	LIB_EXISTS = as.character(lib_exists),
	LIB_INCLUDE_ASSIGN = LIB_INCLUDE_ASSIGN,
	LIB_LINK_ASSIGN = LIB_LINK_ASSIGN
)

# Everything below here is package specific CMake stuff
build_dir = file.path(PACKAGE_BASE_DIR, "src/Imath/build-cran")
if (dir.exists(build_dir)) {
	unlink(build_dir, recursive = TRUE, force = TRUE)
}
dir.create(build_dir, recursive = TRUE, showWarnings = FALSE)

cache_dir = file.path(PACKAGE_BASE_DIR, "src/Imath/build")
dir.create(cache_dir, recursive = TRUE, showWarnings = FALSE)
file_cache = file.path(cache_dir, "initial-cache.cmake")

cache_lines = c(
	'set(CMAKE_C_FLAGS "-g -fPIC -fvisibility=hidden" CACHE STRING "C flags")',
	'set(CMAKE_CXX_FLAGS "-g -fPIC -fvisibility=hidden -fvisibility-inlines-hidden" CACHE STRING "C++ flags")',
	'set(CMAKE_POSITION_INDEPENDENT_CODE ON CACHE BOOL "Position independent code")',
	'set(CMAKE_BUILD_TYPE "Release" CACHE STRING "Build type")',
	'set(BUILD_SHARED_LIBS OFF CACHE BOOL "Build shared libs")'
)
if (is_macos) {
	cache_lines = c(
		cache_lines,
		sprintf(
			'set(CMAKE_OSX_ARCHITECTURES "%s" CACHE STRING "Target architecture")',
			TARGET_ARCH
		)
	)
}
writeLines(cache_lines, file_cache)

read_config_value = function(key) {
	value = r_cmd_config(key)
	if (is.null(value)) {
		return("")
	}
	trimws(paste(value, collapse = " "))
}

first_non_empty = function(values) {
	values = trimws(values)
	values = values[nzchar(values)]
	if (length(values) == 0) {
		return("")
	}
	values[[1]]
}

cc_cmd = first_non_empty(c(
	Sys.getenv("CC", unset = ""),
	read_config_value("CC")
))

cxx_cmd = first_non_empty(c(
	Sys.getenv("CXX20", unset = ""),
	Sys.getenv("CXX17", unset = ""),
	Sys.getenv("CXX14", unset = ""),
	Sys.getenv("CXX11", unset = ""),
	Sys.getenv("CXX", unset = ""),
	read_config_value("CXX20"),
	read_config_value("CXX17"),
	read_config_value("CXX14"),
	read_config_value("CXX11"),
	read_config_value("CXX")
))

inst_dir = file.path(PACKAGE_BASE_DIR, "inst")
dir.create(inst_dir, recursive = TRUE, showWarnings = FALSE)

cmake_cfg = c(
	"..",
	"-C",
	file_cache,
	paste0("-DCMAKE_INSTALL_PREFIX=", inst_dir),
	paste0("-DCMAKE_INSTALL_LIBDIR=lib/", TARGET_ARCH),
	"-DCMAKE_INSTALL_INCLUDEDIR=include",
	"-DIMATH_INSTALL_PKG_CONFIG=ON",
	"-DBUILD_SHARED_LIBS=OFF",
	"-DIMATH_IS_SUBPROJECT=ON",
	"-DCMAKE_BUILD_TYPE=Release",
	"-DCMAKE_POSITION_INDEPENDENT_CODE=ON"
)

cmake_env = character()
if (nzchar(cc_cmd)) {
	cmake_env = c(cmake_env, paste0("CC=", shQuote(cc_cmd)))
	message(sprintf("*** configure: CMake CC='%s'", cc_cmd))
}
if (nzchar(cxx_cmd)) {
	cmake_env = c(cmake_env, paste0("CXX=", shQuote(cxx_cmd)))
	message(sprintf("*** configure: CMake CXX='%s'", cxx_cmd))
}

oldwd = getwd()
setwd(build_dir)
status = system2(CMAKE, cmake_cfg, env = cmake_env)
setwd(oldwd)
if (status != 0) {
	stop("CMake configure step failed")
}

setwd(PACKAGE_BASE_DIR)

lf_ify = function(path) {
	if (!file.exists(path)) {
		return(invisible())
	}
	txt = readLines(path, warn = FALSE) # strips CR automatically
	writeLines(txt, path, sep = "\n", useBytes = TRUE)
}

if (!is_windows) {
	configure_file("src/Makevars.in")
} else {
	configure_file("src/Makevars.win.in")
}

lf_ify("src/Makevars")
lf_ify("src/Makevars.win")

Try the libimath package in your browser

Any scripts or data that you put into this service are public.

libimath documentation built on Feb. 22, 2026, 5:08 p.m.