Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

make generation on linux and compilation on win32 possible #105

Open
wants to merge 15 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion bin/orogen
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,9 @@ parser = OptionParser.new do |opt|
opt.on("--[no-]extended-states", "disable or enable extended states for all tasks defined in this project (enabled by default)") do |flag|
project.extended_states = flag
end
opt.on("--[no-]default-deployment", "disable or enable generating a default deployment for the non-abstract oroGen tasks") do |flag|
project.define_default_deployments = flag
end

opt.on('--no-transports', "disables all transports (by default, #{DEFAULT_TRANSPORTS.join(", ")} are enabled)") do |transport_names|
no_transports = true
Expand Down Expand Up @@ -62,7 +65,7 @@ parser = OptionParser.new do |opt|

opt.on("--target=TARGET", "set the orocos build target (gnulinux or xenomai)") do |target|
target = target.to_s
if target !~ /^(gnulinux|xenomai)$/
if target !~ /^(gnulinux|xenomai|win32)$/
STDERR.puts "unknown target '#{target}', possible values are gnulinux and xenomai"
exit 1
end
Expand Down
8 changes: 5 additions & 3 deletions lib/orogen/gen/project.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,8 @@ def inspect; to_s end
def linux?; orocos_target == 'gnulinux' end
# True if the orocos target is xenomai
def xenomai?; orocos_target == 'xenomai' end
# True if the orocos target is Win32
def win32?; orocos_target == 'win32' end

def enable_namespace(value); @disabled_namespaces.delete(value) end
def disable_namespace(value); @disabled_namespaces << value end
Expand Down Expand Up @@ -682,9 +684,9 @@ def generate
if self_tasks.any?(&:extended_state_support?)
state_types = Generation.render_template(
"tasks", "TaskStates.hpp", binding)
header = Generation.save_automatic(
'typekit', 'types', project.name, "TaskStates.hpp", state_types)
typekit(true).load(header)
header = typekit(true).save_automatic_public_header(
'types', "TaskStates.hpp", state_types)
typekit(true).load(header, relative_path_from: typekit.automatic_public_header_dir)
end

if typekit
Expand Down
9 changes: 0 additions & 9 deletions lib/orogen/gen/tasks.rb
Original file line number Diff line number Diff line change
Expand Up @@ -577,15 +577,6 @@ def generate
validate_constructors(file_cpp, basename)
validate_constructors(file_hpp, basename)

fake_install_dir = File.join(project.base_dir, AUTOMATIC_AREA_NAME, project.name)
FileUtils.mkdir_p fake_install_dir
FileUtils.mkdir_p File.join(fake_install_dir, basepath)

FileUtils.ln_sf File.join(project.base_dir, "tasks",basepath, "#{basename}.hpp"),
File.join(fake_install_dir, basepath, "#{basename}.hpp")
FileUtils.ln_sf File.join(project.base_dir, AUTOMATIC_AREA_NAME, "tasks",basepath, "#{basename}Base.hpp"),
File.join(fake_install_dir, basepath ,"#{basename}Base.hpp")

self
end

Expand Down
166 changes: 73 additions & 93 deletions lib/orogen/gen/typekit.rb
Original file line number Diff line number Diff line change
Expand Up @@ -591,25 +591,13 @@ def self.register_plugin(klass)
# Changes the typekit base directory
def base_dir=(path)
@base_dir = path
if path
include_dirs << path
end
end

INCLUDE_DIR_NAME = 'types'

# Change the directory into which the code generation should be done
def automatic_dir=(path)
@automatic_dir = path
if path
include_dirs << File.join(automatic_dir, INCLUDE_DIR_NAME)
end
end

# Full path to the directory in which includes are either generated
# or symlinked
def includes_dir
File.join(automatic_dir, INCLUDE_DIR_NAME)
end

# The directory in which generated files that are meant to not be
Expand Down Expand Up @@ -812,7 +800,7 @@ def find_type(type, is_normalized = false)
end

rescue Typelib::NotFound => e
if !pending_loads.empty?
if has_pending_loads?
perform_pending_loads
retry
end
Expand Down Expand Up @@ -840,6 +828,7 @@ def initialize(project = nil)

@include_dirs = Set.new
@included_files = Array.new
@local_loads_symlinks = Array.new

@plugins = []
plugins << (TypekitMarshallers::TypeInfo::Plugin.new(self))
Expand Down Expand Up @@ -1130,25 +1119,22 @@ def has_opaques_with_templates?
self_opaques.any? { |op| op.generate_templates? }
end

attr_reader :local_loads_symlinks

# Handle a load that points to a file in this typekit's source tree
def handle_local_load(file)
rel = Pathname.new(file).relative_path_from(Pathname.new(base_dir))
def handle_local_load(file, relative_path_from: base_dir)
rel = Pathname.new(file).relative_path_from(Pathname.new(relative_path_from))
return file if rel.each_filename.first == ".."

local_type_dir = Pathname.new(includes_dir)
rel_to_type_dir = Pathname.new(file).relative_path_from(local_type_dir)
if rel_to_type_dir.each_filename.first == ".."
# If the type is within a subdirectory called as the
# typekit, remove the duplicate
elements = rel.each_filename.to_a
if elements.first != self.name
elements.unshift self.name
end
target = File.join(includes_dir, *elements)
Generation.create_or_update_symlink(file, target)
target
else file
# If the type is within a subdirectory called as the
# typekit, remove the duplicate
elements = rel.each_filename.to_a
if elements.first != self.name
elements.unshift self.name
end
link = File.join(*elements)
@local_loads_symlinks << [file, link]
link
end

# call-seq:
Expand Down Expand Up @@ -1177,41 +1163,36 @@ def handle_local_load(file)
# the exact offsets for all the fields in the structures).
#
# @raises LoadError if the file does not exist
def load(file, add = true, user_options = Hash.new)
if !user_options.respond_to?(:to_hash)
raise ArgumentError, "expected an option has as third argument, got #{user_options.inspect}"
end

def load(file, add = true, relative_path_from: base_dir, **user_options)
if match = /(\w+)\/Types\.hpp$/.match(file)
project_name = match[1]
if project.has_typekit?(project_name) || project.name == project_name
raise ArgumentError, "cannot use a header called #{file} as it clashes with the Types.hpp header generated by orogen for the #{project_name} project"
end
end

include_dirs = self.include_dirs
include_dirs = self.include_dirs.dup
include_dirs << automatic_public_header_dir

# Get the full path for +file+
file =
if File.file?(file) # Local file
File.expand_path(file)
else # File from used libraries/task libraries
dir = include_dirs.find { |dir| File.file?(File.join(dir, file)) }
if !dir
raise LoadError, "cannot find #{file} in #{include_dirs.to_a.join(":")}"
end
loaded_files_dirs << dir
File.join(dir, file)
if File.file?(file) # Local file
file = File.expand_path(file)
include_statement = handle_local_load(file, relative_path_from: relative_path_from)
# Local loads are inserted in a normalized install path at
# loading and build time. They have no full path until then
full_path = nil
else # File from used libraries/task libraries
dir = include_dirs.find { |dir| File.file?(File.join(dir, file)) }
if !dir
raise LoadError, "cannot find #{file} in #{include_dirs.to_a.join(":")}"
end
loaded_files_dirs << dir
full_path = File.join(dir, file)
include_path = include_dirs.map { |d| Pathname.new(d) }
include_statement = resolve_full_include_path_to_relative(full_path, include_path)
end

# If it is a local header, symlink it to the "right" place in
# typekit/types and load that
file = handle_local_load(file)

# And resolve it to an include statement
include_path = include_dirs.map { |d| Pathname.new(d) }
inc = resolve_full_include_path_to_relative(file, include_path)
included_files << inc
included_files << include_statement
user_options[:rawflags] = self.used_libraries.
map { |lib| lib.raw_cflags_only_other }.
flatten.uniq
Expand All @@ -1222,7 +1203,7 @@ def load(file, add = true, user_options = Hash.new)
end

@pending_load_options = this_options
pending_loads << file
pending_loads << [full_path, include_statement]
end

def filter_unsupported_types(registry)
Expand Down Expand Up @@ -1449,14 +1430,17 @@ def resolve_toplevel_include_mapping(toplevel_files, options)
return preprocessed, owners
end

def make_load_options(pending_loads, user_options)
options = { :opaques_ignore => true, :merge => false, :required_files => pending_loads.to_a }
def make_load_options(required_files, user_options)
user_options = user_options.dup
options = { opaques_ignore: true, merge: false, required_files: required_files }
# GCCXML can't parse vectorized code, and the Typelib internal
# parser can't parse eigen at all. It is therefore safe to do it
# here
options[:define] = ["OROCOS_TARGET=#{RTT_CPP.orocos_target}", '__orogen2']

options[:include] = self.include_dirs.dup
options[:include] = (user_options.delete(:include) || Set.new).to_set |
self.include_dirs |
[automatic_public_header_dir]
options = options.merge(user_options) do |key, a, b|
if a.respond_to?(:to_ary)
if b.respond_to?(:to_ary)
Expand Down Expand Up @@ -1491,29 +1475,32 @@ def has_pending_loads?
end

def perform_pending_loads
return if pending_loads.empty?
loads = pending_loads.dup
pending_loads.clear
return if !has_pending_loads?

add, user_options = *pending_load_options
fake_include_dir = Dir.mktmpdir
@local_loads_symlinks.each do |target, link|
FileUtils.mkdir_p File.join(fake_include_dir, File.dirname(link))
FileUtils.cp target, File.join(fake_include_dir, link)
end

include_dirs = self.include_dirs.to_a
if automatic_dir
include_dirs << File.join(automatic_dir, "types")
pending_loads_to_relative = Hash.new
loads = pending_loads.map do |full_path, include_statement|
full_path ||= File.join(fake_include_dir, include_statement)
pending_loads_to_relative[full_path] = include_statement
full_path
end
pending_loads.clear

add, user_options = *pending_load_options

file_registry = Typelib::Registry.new
file_registry.merge opaque_registry

preprocess_options, options = make_load_options(loads, user_options)
options[:include] << fake_include_dir
preprocessed, include_mappings = resolve_toplevel_include_mapping(loads, preprocess_options)

include_path = include_dirs.map { |d| Pathname.new(d) }
pending_loads_to_relative = loads.inject(Hash.new) do |map, path|
map[path] = resolve_full_include_path_to_relative(path, include_path)
map
end

include_paths = options[:include].map { |p| Pathname.new(p) }
include_mappings.each do |file, lines|
lines.map! { |inc| pending_loads_to_relative[inc] }
end
Expand All @@ -1539,6 +1526,10 @@ def perform_pending_loads
if add
self.loads.concat(loads.to_a)
end
ensure
if fake_include_dir
FileUtils.remove_entry fake_include_dir
end
end

METADATA_RELATED_TYPES = ['bitfield']
Expand Down Expand Up @@ -1814,8 +1805,8 @@ def handle_opaques_generation(generated_types)
marshalling_code = Generation.
render_template 'typekit', 'marshalling_types.hpp', binding

path = Generation.save_automatic 'typekit', 'types', self.name, "m_types", "#{type.method_name(true)}.hpp", marshalling_code
self.load(path, true, options)
path = save_automatic_public_header "m_types", "#{type.method_name(true)}.hpp", marshalling_code
self.load(path, true, relative_path_from: automatic_public_header_dir, **options)

m_type = intermediate_type_for(type)
copy_metadata_to_intermediate_type(type.metadata, m_type.metadata)
Expand Down Expand Up @@ -1914,10 +1905,14 @@ def code_fromIntermediate(intermediate_type, needs_copy, indent)

attr_reader :template_instanciation_files

def automatic_public_header_dir
File.join(automatic_dir, '__include_dir__')
end

def save_automatic_public_header(*args)
rel = File.join(self.name, 'typekit', *args[0..-2])
Generation.save_generated(true, automatic_dir, INCLUDE_DIR_NAME, rel, args[-1])
rel
Generation.save_generated(true, automatic_public_header_dir, rel, args[-1])
File.join(automatic_public_header_dir, rel)
end

def save_automatic(*args)
Expand Down Expand Up @@ -1972,26 +1967,15 @@ def map_typeset_to_registry(registry, types)
types.map { |t| find_type(t) }.to_set
end

def relative_path_from_automatic(path)
auto = Pathname.new(automatic_dir)
Pathname.new(path).relative_path_from(auto).to_s
end

def generate
typekit = self

FileUtils.mkdir_p automatic_dir

# Populate a fake installation directory so that the include
# files can be referred to as <project_name>/header.h
fake_install_dir = File.join(automatic_dir, name)

# Upgrade from directory to symlink
if !File.symlink?(fake_install_dir)
FileUtils.rm_rf fake_install_dir
end
Generation.create_or_update_symlink(automatic_dir, fake_install_dir)

if standalone?
fake_typekit_dir = File.join(automatic_dir, "typekit")
Generation.create_or_update_symlink(automatic_dir, fake_typekit_dir)
end

# Generate opaque-related stuff first, so that we see them in
# the rest of the typelib-registry-manipulation code
handle_opaques_generation(registry)
Expand Down Expand Up @@ -2167,10 +2151,6 @@ def generate
save_user("Opaques.hpp", user_hh)
implementation_files <<
save_user("Opaques.cpp", user_cc)

Generation.create_or_update_symlink(
File.join(user_dir, "Opaques.hpp"),
File.join(automatic_dir, INCLUDE_DIR_NAME, self.name, 'typekit', "Opaques.hpp"))
end
end

Expand Down
Loading