FFI::ClangSourceFFIClangArgs

class Args

Platform-specific clang configuration: finding libclang, locating the resource directory, and injecting extra command-line arguments into parse_translation_unit.

All discovery is lazy — nothing runs until a method is called.

Definitions

attr_writer :libclang_loaded_path

Set the loaded libclang path after ffi_lib succeeds, so resource dir probing can use it.

Signature

parameter path String | Nil

Path to the loaded libclang library.

def self.create

Factory: returns the platform-appropriate subclass instance.

Signature

returns Args

A platform-specific instance.

Implementation

def self.create
	case FFI::Clang.platform
	when :darwin
		DarwinArgs.new
	when :mingw
		MingwArgs.new
	when :mswin
		MswinArgs.new
	else
		LinuxArgs.new
	end
end

def libclang_paths

Ordered list of library paths for ffi_lib.

Signature

returns Array(String)

Paths to try when loading libclang.

Implementation

def libclang_paths
	@libclang_paths ||= if ENV["LIBCLANG"]
		[ENV["LIBCLANG"]]
	else
		find_libclang_paths
	end
end

def command_line_args(command_line_args = [])

Extra args to inject into parse_translation_unit. Includes -resource-dir (unless already present) plus any platform-specific flags.

Signature

parameter command_line_args Array(String)

The existing command line arguments.

returns Array(String)

Additional args to append.

Implementation

def command_line_args(command_line_args = [])
	args = []
	
	if !command_line_args.include?("-resource-dir") && resource_dir
		args.push("-resource-dir", resource_dir)
	end
	
	args.concat(extra_args(command_line_args))
	args
end

def resource_dir

The resolved resource directory path.

Signature

returns String | Nil

The resource directory path, or nil if not found.

Implementation

def resource_dir
	if defined?(@resource_dir)
		@resource_dir
	else
		@resource_dir = find_resource_dir
	end
end

def post_load(library)

Called after ffi_lib successfully loads libclang. Subclasses may override to perform post-load setup.

Signature

parameter library FFI::DynamicLibrary

The loaded libclang library.

Implementation

def post_load(library)
end

def extra_args(command_line_args)

Platform-specific extra args beyond -resource-dir. Subclasses override as needed.

Signature

parameter command_line_args Array(String)

The existing command line arguments.

returns Array(String)

Additional platform-specific args.

Implementation

def extra_args(command_line_args)
	[]
end

def llvm_config

Find the llvm-config binary. Checks LLVM_CONFIG env, then PATH (unless LLVM_VERSION is set to pin a specific version).

Signature

returns String | Nil

Path to llvm-config, or nil.

Implementation

def llvm_config
	if defined?(@llvm_config)
		return @llvm_config
	end
	
	@llvm_config = ENV["LLVM_CONFIG"]
	
	unless @llvm_config || ENV["LLVM_VERSION"]
		@llvm_config = "llvm-config"
	end
	
	@llvm_config
end

def llvm_library_dir

Query llvm-config for its library directory.

Signature

returns String | Nil

The library directory, or nil.

Implementation

def llvm_library_dir
	return nil unless llvm_config
	
	@llvm_library_dir ||= run_command(llvm_config, "--libdir")
end

def llvm_bin_dir

Query llvm-config for its binary directory.

Signature

returns String | Nil

The binary directory, or nil.

Implementation

def llvm_bin_dir
	return nil unless llvm_config
	
	@llvm_bin_dir ||= run_command(llvm_config, "--bindir")
end

def resource_dir_from_clang(clang)

Ask a clang binary for its resource directory.

Signature

parameter clang String

Path to or name of the clang binary.

returns String | Nil

The resource directory path, or nil.

Implementation

def resource_dir_from_clang(clang)
	dir = run_command(clang, "-print-resource-dir")
	valid_resource_dir?(dir) ? dir : nil
end

def probe_from_libclang(libclang_path)

Probe for the resource directory relative to the libclang shared library.

Signature

parameter libclang_path String

Path to the libclang shared library.

returns String | Nil

The resource directory path, or nil.

Implementation

def probe_from_libclang(libclang_path)
	base = ::File.expand_path(::File.dirname(libclang_path))
	
	candidates = []
	candidates.concat Dir.glob(::File.join(base, "..", "lib", "clang", "*"))
	candidates.concat Dir.glob(::File.join(base, "..", "..", "lib", "clang", "*"))
	candidates.concat Dir.glob(::File.join(base, "clang", "*"))
	
	candidates = candidates.map{|p| ::File.expand_path(p)}.uniq
	
	candidates
		.select{|dir| valid_resource_dir?(dir)}
		.sort
		.last
end

def valid_resource_dir?(dir)

Check whether a directory looks like a valid clang resource directory.

Signature

parameter dir String | Nil

The directory to check.

returns Boolean

True if the directory contains expected compiler headers.

Implementation

def valid_resource_dir?(dir)
	return false unless dir && ::File.directory?(dir)
	
	inc = ::File.join(dir, "include")
	return false unless ::File.directory?(inc)
	
	::File.exist?(::File.join(inc, "stddef.h")) ||
		::File.exist?(::File.join(inc, "__stddef_size_t.h")) ||
		::File.exist?(::File.join(inc, "stdint.h"))
end

def find_resource_dir

Common resource dir search: env override, clang from llvm-config, clang on PATH, probe from loaded libclang.

Signature

returns String | Nil

The resource directory path, or nil.

Implementation

def find_resource_dir
	# 1. Explicit override via environment variable.
	env = ENV["LIBCLANG_RESOURCE_DIR"]
	return env if valid_resource_dir?(env)
	
	# 2. Clang binary from llvm-config.
	if (bin_dir = llvm_bin_dir)
		clang_path = ::File.join(bin_dir, "clang")
		if (dir = resource_dir_from_clang(clang_path))
			return dir
		end
	end
	
	# 3. clang on PATH.
	if (dir = resource_dir_from_clang("clang"))
		return dir
	end
	
	# 4. Probe relative to the loaded libclang shared library.
	if @libclang_loaded_path && (dir = probe_from_libclang(@libclang_loaded_path))
		return dir
	end
	
	nil
end