class MxxRu::Cpp::ExtCMakeProjectTarget

External CMake project.

Since v.1.6.11

Constants

INSTALL_MANIFEST

Public Class Methods

new( a_alias, &block ) click to toggle source
Calls superclass method MxxRu::Cpp::CompositeTarget::new
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 71
def initialize( a_alias, &block )
  @mxx_cmake_defs = {}
  @mxx_includedir_subfolders = []

  super( a_alias )

  if @mxx_cmakelists_location.nil?
    raise CMakeProjectLocationNotDefined.new( a_alias )
  end
end

Public Instance Methods

build() click to toggle source
Calls superclass method MxxRu::Cpp::CompositeTarget#build
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 204
def build
  if nil == @mxx_last_build_result
    super

    # Actual result must be set only after CMake-related build steps.
    @mxx_last_build_result = nil
    @mxx_last_build_result = do_cmake_specific_build
  end

  @mxx_last_build_result
end
build_dir_name( name ) click to toggle source

Set the name of folder in which cmake-controlled build will be performed. If this name is not specified then name of that folder will be generated automatically (it will be based on toolset name and build mode).

Note: this folder is always created in location defined by obj_placement. Because of that is cannot be absolute path.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 125
def build_dir_name( name )
  @mxx_cmake_build_dir_name = name
end
clean() click to toggle source
Calls superclass method MxxRu::Cpp::CompositeTarget#clean
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 216
def clean
  do_cmake_specific_clean
  super
end
includedir_subfolder( name ) click to toggle source

Set a name of includedir subfolder to be added to include path of all dependent targets.

Sometimes a project can have several subfolder in its include directory. Something like that:

some_project
`- include/
   `- subfolder1/
   `- subfolder2/
   `- subfolder3

When cmake install will be performed all these subfolders will be installed into install_includedir. But only install_includedir will be added to include path. It means that header files from these subfolders must be included as:

#include <subfolder1/first_header.hpp>
#include <subfolder2/second_header.hpp>
...

It could be inappropriate. In that case includedir_subfolder can be used:

MxxRu::Cpp::ext_cmake_project {
  where 'soci'

  install_includedir 'soci_headers'
  includedir_subfolder 'soci'
  includedir_subfolder 'soci/postgresql'
  ...
}
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 179
def includedir_subfolder( name )
  @mxx_includedir_subfolders << name
end
includedir_subfolders( *names ) click to toggle source

Same as includedir_subfolder but allow to specify several folder names at once.

For example:

MxxRu::Cpp::ext_cmake_project {
  where 'soci'

  install_includedir 'soci_headers'
  includedir_subfolders 'soci', 'soci/postgresql'
  ...
}
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 196
def includedir_subfolders( *names )
  @mxx_includedir_subfolders.push( *names )
end
install_includedir( dir ) click to toggle source

Set name of folder for header files.

This name will be passed to cmake command via -DINCLUDEDIR option.

Usage example:

MxxRu::Cpp::ext_cmake_project {
  where 'soci'

  install_includedir 'soci_headers'
  ...
}
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 142
def install_includedir( dir )
  @mxx_cmake_install_includedir = dir
end
target_type() click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 200
def target_type
  return ExtCMakeProjectTargetType.new
end
where( location ) click to toggle source

Set the location of external project's CMakeLists.txt file.

This is mandatory parameter.

NOTE. location must be a relative path.

Usage example:

MxxRu::Cpp::ext_cmake_project {
  where 'soci' # It means that 'soci' must be subfolder of
               # the prject's root folder.
  ...
}
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 96
def where( location )
  @mxx_cmakelists_location = location
end
with( options ) click to toggle source

Set values to be passes to cmake commands via -D option.

Usage example:

MxxRu::Cpp::ext_cmake_project {
  where 'soci'

  with WITH_BOOST: :ON, WITH_ORACLE: :OFF
  with :SOCI_EMPTY => 'OFF'
  with :SOCI_SHARED => 'ON', :SOCI_STATIC => 'OFF'
  with SOCI_TESTS: :OFF
}
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 113
def with( options )
  @mxx_cmake_defs.merge!( options )
end

Private Instance Methods

clean_installed_files() click to toggle source

NOTE. This method must be called when cmake working dir is the current directory.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 336
def clean_installed_files
  do_with_install_manifest_content do |file_to_remove|
    if File.exists?( file_to_remove )
      FileUtils.rm( file_to_remove, file_utils_options )
    end
  end
end
compare_build_results_states( old_state, new_state ) click to toggle source

Compares old and new states and returns TargetState::EXISTS or TargetState::REBUILT

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 293
def compare_build_results_states( old_state, new_state )
  # Keeps files which are not present in old_state or
  # files with new modification time.
  new_state.keep_if do |name, mtime|
    old_mtime = old_state.fetch( name, nil )
    old_mtime.nil? ? true : (old_mtime < mtime)
  end
  new_state.empty? ? TargetState::EXISTS : TargetState::REBUILT
end
create_cmake_build_dir_value() click to toggle source

Create local name of cmake working directory. If `cmake_build_dir` is specified then its value will be used. Otherwise a name based on toolset id string and build mode will be created.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 394
def create_cmake_build_dir_value
  if @mxx_cmake_build_dir_name.nil?
    v = "cmake_build_#{toolset.make_identification_string}_"
    v += RUNTIME_RELEASE == mxx_runtime_mode ? "release" : "debug"
  else
    @mxx_cmake_build_dir_name
  end
end
detect_build_results_state() click to toggle source

Returns hash where key is a file name and value is file modification time.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 280
def detect_build_results_state
  result = {}
  do_with_install_manifest_content do |filename|
    if File.exists?( filename )
      result[ filename ] = File.mtime( filename )
    end
  end
  result
end
detect_cmake_build_type() click to toggle source

Returns value for CMAKE_BUILD_TYPE definition.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 411
def detect_cmake_build_type
  RUNTIME_RELEASE == mxx_runtime_mode ? "Release" : "Debug"
end
detect_cmake_compilers() click to toggle source

Make part of cmake command line with CMAKE_C_COMPILER and CMAKE_CXX_COMPILER definitions.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 441
def detect_cmake_compilers
  "-DCMAKE_C_COMPILER=#{toolset.c_compiler_name} " +
  "-DCMAKE_CXX_COMPILER=#{toolset.cpp_compiler_name} "
end
detect_cmake_generator() click to toggle source

Make part of cmake command line with '-G' option and appropriate value for it.

NOTE: if there is no known generator name for the toolset then empty string is returned.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 420
def detect_cmake_generator
  if 'vc' == toolset.name
    '-G "NMake Makefiles"'
  elsif 'gcc' == toolset.name
    k = MxxRu::Cpp::Toolsets::GccFamily
    if k::GCC_PORT_MINGW == toolset.tag( k::GCC_PORT_TAG, 'unix' )
      '-G "MinGW Makefiles"'
    else
      '-G "Unix Makefiles"'
    end
  elsif 'clang' == toolset.name
    '-G "Unix Makefiles"'
  else
    # Return empty string in hope that CMake can detect a generator
    # by itself.
    ''
  end
end
do_cmake_specific_build() click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 224
def do_cmake_specific_build
  ctx = make_building_context

  if !MxxRu::Util::Mode.instance.is_dry_run
    try_run_cmake_build( ctx )
  else
    TargetState.new( TargetState::REBUILT )
  end
end
do_cmake_specific_clean() click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 234
def do_cmake_specific_clean
  ctx = make_building_context

  if !MxxRu::Util::Mode.instance.is_dry_run
    try_run_cmake_clean( ctx )
  end
end
do_with_install_manifest_content(&block) click to toggle source

Open INSTALL_MANIFEST if it exists and call block for every non-empty name from it.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 355
def do_with_install_manifest_content(&block)
  if File.exists?( INSTALL_MANIFEST )
    File::open( INSTALL_MANIFEST, 'r' ) do |manifest|
      manifest.each_line do |line|
        filename = line.chomp
        block[ line.chomp ] unless filename.empty?
      end
    end
  end
end
file_utils_options() click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 446
def file_utils_options
  { :verbose => MxxRu::Util::Mode::instance.is_brief_desc }
end
make_building_context() click to toggle source

Create instance of BuildingContext with all members initialized with appropriate values.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 368
def make_building_context
  ctx = BuildingContext.new
  ctx.cmakelists_location = File.absolute_path( @mxx_cmakelists_location )
  ctx.install_prefix = File.absolute_path(
      mxx_obj_placement.get_lib( '.', toolset, self ) )

  includedir = @mxx_cmake_install_includedir
  includedir = 'include' unless includedir
  ctx.install_includedir =
      File.absolute_path(
          mxx_obj_placement.get_lib( includedir, toolset, self ) )

  ctx.install_libdir = File.absolute_path(
      mxx_obj_placement.get_lib( '.', toolset, self ) )

  ctx.cmake_build_dir = File.join(
      mxx_obj_placement.get_obj( @mxx_cmakelists_location, toolset, self ),
      create_cmake_build_dir_value )

  ctx
end
run_cmake( ctx ) click to toggle source

NOTE. This method must be called when cmake working dir is the current directory.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 305
def run_cmake( ctx )
  cmd_line = "cmake -DCMAKE_BUILD_TYPE=#{detect_cmake_build_type} "
  cmd_line += "-DCMAKE_INSTALL_PREFIX=#{ctx.install_prefix} "

  cmd_line += "-DINCLUDEDIR=#{ctx.install_includedir} " if ctx.install_includedir

  cmd_line += "-DLIBDIR=#{ctx.install_libdir} " if ctx.install_libdir
  cmd_line += "-DBINDIR=#{ctx.install_bindir} " if ctx.install_bindir
  cmd_line += transform_options_to_cmd_line_params

  cmd_line += detect_cmake_compilers
  cmd_line += "#{detect_cmake_generator} "

  cmd_line += ctx.cmakelists_location
  AbstractTarget::run(
      [cmd_line],
      [],
      "Running CMake for native build files configuration" )
end
run_native_build() click to toggle source

NOTE. This method must be called when cmake working dir is the current directory.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 327
def run_native_build
  AbstractTarget::run(
      ["cmake --build . --target install"],
      [],
      "Launching native build via CMake" )
end
run_native_clean() click to toggle source

NOTE. This method must be called when cmake working dir is the current directory.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 346
def run_native_clean
  AbstractTarget::run(
      ["cmake --build . --target clean"],
      [],
      "Launching native clean via CMake" )
end
transform_options_to_cmd_line_params() click to toggle source

Make part of cmake command line with definitions from 'with' values.

# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 404
def transform_options_to_cmd_line_params
  r = ''
  @mxx_cmake_defs.each_pair { |k,v| r += "-D#{k}=#{v} " }
  r
end
try_run_cmake_build( ctx ) click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 242
def try_run_cmake_build( ctx )
  # Assume that target is rebuilt.
  # Actual state will be detected later.
  target_state = TargetState::REBUILT

  MxxRu::Util::ensure_path_exists( ctx.cmake_build_dir )
  FileUtils.cd( ctx.cmake_build_dir ) do
    pre_build_state = detect_build_results_state

    run_cmake( ctx )
    run_native_build

    target_state = compare_build_results_states(
        pre_build_state, detect_build_results_state )
  end

  # If everything is all right then include path and library paths
  # must be set for all dependent targets.
  include_path( ctx.install_includedir, OPT_UPSPREAD )
  @mxx_includedir_subfolders.each do |folder|
    include_path( File.join( ctx.install_includedir, folder ), OPT_UPSPREAD )
  end
  lib_path( ctx.install_libdir )

  TargetState.new( target_state )
end
try_run_cmake_clean( ctx ) click to toggle source
# File lib/mxx_ru/cpp/ext_cmake_project.rb, line 269
def try_run_cmake_clean( ctx )
  if File.directory?( ctx.cmake_build_dir )
    FileUtils.cd( ctx.cmake_build_dir ) do
      clean_installed_files
      run_native_clean
    end
    FileUtils.rm_r( ctx.cmake_build_dir, file_utils_options )
  end
end