class Autobuild::CMake
Handler class to build CMake-based packages
Constants
- CMAKE_EQVS
- DOXYGEN_ACCEPTED_VARIABLES
Attributes
Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake
This is experimental and OFF by default. See CMake#run_doxygen
for more details
See also CMake#always_use_doc_target=
and CMake#always_use_doc_target?
for a per-package control of that feature
Global default for the CMake
generator to use. If nil (the default), the -G option will not be given at all. Will work only if the generator creates makefiles
It can be overriden on a per-package basis with CMake.generator=
If true, always run cmake before make during the build
Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake
This is experimental and OFF by default. See CMake#run_doxygen
for more details
See also CMake.always_use_doc_target=
and CMake.always_use_doc_target?
for a global control of that feature
a key => value association of defines for CMake
If true, we always remove the CMake
cache before reconfiguring.
See full_reconfigures?
for more details
Sets a generator explicitely for this component. See generator
and CMake.generator
Public Class Methods
Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake
This is experimental and OFF by default. See CMake#run_doxygen
for more details
See also CMake#always_use_doc_target=
and CMake#always_use_doc_target?
for a per-package control of that feature
# File lib/autobuild/packages/cmake.rb, line 185 def always_use_doc_target? @always_use_doc_target end
# File lib/autobuild/packages/cmake.rb, line 12 def builddir @builddir || Configurable.builddir end
# File lib/autobuild/packages/cmake.rb, line 16 def builddir=(new) if Pathname.new(new).absolute? raise ConfigException, "absolute builddirs are not supported" end if new.nil? || new.empty? raise ConfigException, "builddir must be non-nil and non-empty" end @builddir = new end
# File lib/autobuild/packages/cmake.rb, line 136 def self.define(name, value) @@defines[name] = if value.respond_to?(:to_str) value.to_str elsif value 'ON' else 'OFF' end end
# File lib/autobuild/packages/cmake.rb, line 132 def self.defines @@defines end
Set {#delete_obsolete_files_in_prefix?}
# File lib/autobuild/packages/cmake.rb, line 53 def delete_obsolete_files_in_prefix=(flag) @@delete_obsolete_files_in_prefix = flag end
Whether files that are not within CMake’s install manifest but are present in the prefix should be deleted. Note that the contents of {#log_dir} are unaffected.
It is false by default. Set to true only if each package has its own prefix.
# File lib/autobuild/packages/cmake.rb, line 48 def delete_obsolete_files_in_prefix? @@delete_obsolete_files_in_prefix end
# File lib/autobuild/packages/cmake.rb, line 29 def full_reconfigures? @full_reconfigures end
Autobuild::Configurable::new
# File lib/autobuild/packages/cmake.rb, line 115 def initialize(options) @defines = Hash.new super @delete_obsolete_files_in_prefix = self.class. delete_obsolete_files_in_prefix? end
# File lib/autobuild/packages/cmake.rb, line 480 def self.show_make_messages=(value) @show_make_messages = value end
# File lib/autobuild/packages/cmake.rb, line 476 def self.show_make_messages? @show_make_messages end
Public Instance Methods
The list of all -D options that should be passed on to CMake
# File lib/autobuild/packages/cmake.rb, line 68 def all_defines additional_defines = Hash[ "CMAKE_INSTALL_PREFIX" => prefix, "CMAKE_MODULE_PATH" => module_path.join(";"), "CMAKE_PREFIX_PATH" => prefix_path.join(";")] self.class.defines.merge(additional_defines).merge(defines) end
Flag controlling whether autobuild should run doxygen itself or use the “doc” target generated by CMake
This is experimental and OFF by default. See CMake#run_doxygen
for more details
See also CMake.always_use_doc_target=
and CMake.always_use_doc_target?
for a global control of that feature
# File lib/autobuild/packages/cmake.rb, line 209 def always_use_doc_target? if @always_use_doc_target.nil? CMake.always_use_doc_target? else @always_use_doc_target end end
Do the build in builddir
# File lib/autobuild/packages/cmake.rb, line 485 def build current_message = +"" in_dir(builddir) do progress_start "building %s" do if always_reconfigure || !File.file?('Makefile') run('build', Autobuild.tool(:cmake), '.') end warning_count = 0 Autobuild.make_subcommand(self, 'build') do |line| needs_display = false if line =~ /\[\s*(\d+)%\]/ progress "building %s (#{Integer($1)}%)" elsif line !~ /^(?:Generating|Linking|Scanning|Building|Built)/ warning_count += 1 if line =~ /warning/ if show_make_messages? current_message += line + "\n" needs_display = true end end if !needs_display && !current_message.empty? current_message.split("\n").each do |l| message "%s: #{l}", :magenta end current_message.clear end end current_message.split("\n").each do |l| message "%s: #{l}", :magenta end if warning_count > 0 msg_warning = Autoproj.color("(#{warning_count} warnings)", :bold) progress_done "built %s #{msg_warning}" else progress_done "built %s" end end end Autobuild.touch_stamp(buildstamp) rescue ::Exception current_message.split("\n").each do |l| message "%s: #{l}", :magenta end raise end
# File lib/autobuild/packages/cmake.rb, line 107 def cmake_cache File.join(builddir, "CMakeCache.txt") end
# File lib/autobuild/packages/cmake.rb, line 272 def common_utility_handling( # rubocop:disable Metrics/ParameterLists utility, target, *args, start_msg, done_msg, post_process: nil ) utility.source_ref_dir = builddir utility.task do progress_start start_msg, :done_message => done_msg do if internal_doxygen_mode? run_doxygen else run(utility.name, Autobuild.tool(:make), "-j#{parallel_build_level}", target, *args, working_directory: builddir) end yield if block_given? end post_process&.call end end
Configure the builddir directory before starting make
Autobuild::Configurable#configure
# File lib/autobuild/packages/cmake.rb, line 436 def configure super do in_dir(builddir) do unless File.file?(File.join(srcdir, 'CMakeLists.txt')) raise ConfigException.new(self, 'configure'), "#{srcdir} contains no CMakeLists.txt file" end command = ["cmake"] if Autobuild.windows? command << '-G' command << "MSYS Makefiles" end all_defines.each do |name, value| command << "-D#{name}=#{value}" end command << Array(generator).map { |g| "-G#{g}" } if generator command << srcdir progress_start "configuring CMake for %s", done_message: "configured CMake for %s" do FileUtils.rm_f cmake_cache if full_reconfigures? run('configure', *command) end end end end
# File lib/autobuild/packages/cmake.rb, line 111 def configurestamp cmake_cache end
# File lib/autobuild/packages/cmake.rb, line 303 def coverage_block proc do next unless test_utility.coverage_enabled? next unless @with_coverage progress_start "generating coverage report for %s", done_message: "generated coverage report for %s" do @with_coverage.call end end end
# File lib/autobuild/packages/cmake.rb, line 147 def define(name, value) @defines[name] = if value.respond_to?(:to_str) value.to_str elsif value 'ON' else 'OFF' end end
# File lib/autobuild/packages/cmake.rb, line 386 def defines_changed?(all_defines, cache_data) all_defines.any? do |name, value| if (match = /^#{name}:\w+=(.*)$/.match(cache_data)) old_value = match[1] end value = value.to_s if !old_value || !equivalent_option_value?(old_value, value) if Autobuild.debug message "%s: option '#{name}' changed value: "\ "'#{old_value}' => '#{value}'" end if old_value message "%s: changed value of #{name} "\ "from #{old_value} to #{value}" else message "%s: setting value of #{name} to #{value}" end true end end end
@api private
Delete files in {#prefix} that are not present in CMake’s install manifest
This is enabled globally by {CMake.delete_obsolete_files_in_prefix=} or per-package with {#delete_obsolete_files_in_prefix=}. Do NOT enable if packages share the same prefix.
# File lib/autobuild/packages/cmake.rb, line 555 def delete_obsolete_files # The expand_path is required to sanitize the paths, which can # contain e.g. double // cmake_install_manifest = File.join(builddir, 'install_manifest.txt') manifest_contents = File.readlines(cmake_install_manifest). map { |p| File.expand_path(p.chomp) }.to_set logdir = self.logdir counter = 0 Find.find(prefix) do |path| Find.prune if path == logdir if !manifest_contents.include?(path) && File.file?(path) counter += 1 FileUtils.rm path end end if counter > 0 message "%s: removed #{counter} obsolete files from prefix (cmake)" end end
(see CMake.delete_obsolete_files_in_prefix?
)
# File lib/autobuild/packages/cmake.rb, line 123 def delete_obsolete_files_in_prefix? @delete_obsolete_files_in_prefix end
# File lib/autobuild/packages/cmake.rb, line 337 def equivalent_option_value?(old, new) if old == new true else old = CMAKE_EQVS[old] new = CMAKE_EQVS[new] if old && new old == new else false end end end
If true, we always remove the CMake
cache before reconfiguring. This is to workaround the aggressive caching behaviour of CMake
, and is set to true by default.
See CMake.full_reconfigures?
and CMake.full_reconfigures=
for a global setting
# File lib/autobuild/packages/cmake.rb, line 99 def full_reconfigures? if @full_reconfigures.nil? CMake.full_reconfigures? else @full_reconfigures end end
The CMake
generator to use. You must choose one that generates Makefiles. If not set for this package explicitely, it is using the global value CMake.generator
.
# File lib/autobuild/packages/cmake.rb, line 89 def generator @generator || CMake.generator end
# File lib/autobuild/packages/cmake.rb, line 351 def import(**options) super Dir.glob(File.join(srcdir, "*.pc.in")) do |file| file = File.basename(file, ".pc.in") provides "pkgconfig/#{file}" end end
Install the result in prefix
If {#delete_obsolete_files_in_prefix?} is set, files that are present in the prefix but not in CMake’s install manifest will be removed.
# File lib/autobuild/packages/cmake.rb, line 535 def install in_dir(builddir) do progress_start "installing %s", done_message: 'installed %s' do run('install', Autobuild.tool(:make), "-j#{parallel_build_level}", 'install') end delete_obsolete_files if delete_obsolete_files_in_prefix? end super end
To avoid having to build packages to run the documentation target, we try to autodetect whether (1) the package is using doxygen and (2) whether the cmake variables in the doxyfile can be provided by autobuild itself.
This can be disabled globally by setting Autobuild::CMake.always_use_doc_target=
or on a per-package basis with always_use_doc_target=
This method returns true if the package can use the internal doxygen mode and false otherwise
# File lib/autobuild/packages/cmake.rb, line 228 def internal_doxygen_mode? return false if always_use_doc_target? doxyfile_in = File.join(srcdir, "Doxyfile.in") return false unless File.file?(doxyfile_in) File.readlines(doxyfile_in).each do |line| matches = line.scan(/@[^@]+@/) if matches.any? { |str| !DOXYGEN_ACCEPTED_VARIABLES.key?(str) } return false end end end
# File lib/autobuild/packages/cmake.rb, line 360 def module_path CMake.module_path end
# File lib/autobuild/packages/cmake.rb, line 364 def prefix_path seen = Set.new result = Array.new raw = (dependencies.map { |pkg_name| Autobuild::Package[pkg_name].prefix } + CMake.prefix_path) raw.each do |path| unless seen.include?(path) seen << path result << path end end result end
Autobuild::Configurable#prepare
# File lib/autobuild/packages/cmake.rb, line 411 def prepare # A failed initial CMake configuration leaves a CMakeCache.txt file, # but no Makefile. # # Delete the CMakeCache to force reconfiguration unless File.exist?(File.join(builddir, 'Makefile')) FileUtils.rm_f(cmake_cache) end doc_utility.source_ref_dir = builddir if File.exist?(cmake_cache) cache = File.read(cmake_cache) if defines_changed?(all_defines, cache) if Autobuild.debug message "%s: CMake configuration changed, forcing a reconfigure" end FileUtils.rm_f cmake_cache end end super end
To avoid having to build packages to run the documentation target, we try to autodetect whether (1) the package is using doxygen and (2) whether the cmake variables in the doxyfile can be provided by autobuild itself.
This can be disabled globally by setting Autobuild::CMake.always_use_doc_target
or on a per-package basis with always_use_doc_target
This method generates the corresponding doxygen file in <builddir>/Doxygen and runs doxygen. It raises if the internal doxygen support cannot be used on this package
# File lib/autobuild/packages/cmake.rb, line 254 def run_doxygen doxyfile_in = File.join(srcdir, "Doxyfile.in") unless File.file?(doxyfile_in) raise "no Doxyfile.in in this package, "\ "cannot use the internal doxygen support" end doxyfile_data = File.readlines(doxyfile_in).map do |line| line.gsub(/@[^@]+@/) do |match| DOXYGEN_ACCEPTED_VARIABLES[match].call(self) end end doxyfile = File.join(builddir, "Doxyfile") File.open(doxyfile, 'w') do |io| io.write(doxyfile_data) end run('doc', Autobuild.tool(:doxygen), doxyfile) end
# File lib/autobuild/packages/cmake.rb, line 575 def self_fingerprint return unless (base = super) all_defines = self.class.defines.merge(defines).sort_by(&:first) Digest::SHA1.hexdigest(base + all_defines.join("")) end
# File lib/autobuild/packages/cmake.rb, line 466 def show_make_messages? if !@show_make_messages.nil? @show_make_messages else CMake.show_make_messages? end end
# File lib/autobuild/packages/cmake.rb, line 379 def update_environment super prefix_path.each do |p| env_add_path 'CMAKE_PREFIX_PATH', p end end
# File lib/autobuild/packages/cmake.rb, line 299 def with_coverage(&block) @with_coverage ||= block end
Declare that the given target can be used to generate documentation
# File lib/autobuild/packages/cmake.rb, line 316 def with_doc(target = 'doc', &block) common_utility_handling( doc_utility, target, "generating documentation for %s", "generated documentation for %s", &block) end
# File lib/autobuild/packages/cmake.rb, line 323 def with_tests(target = 'test', &block) common_utility_handling( test_utility, target, "ARGS=-V", "running tests for %s", "successfully ran tests for %s", post_process: coverage_block, &block) end