diff --git a/cxx.gemspec b/cxx.gemspec index 259b29b..fe17c2b 100644 --- a/cxx.gemspec +++ b/cxx.gemspec @@ -2,7 +2,7 @@ require 'rake' include FileUtils -PKG_VERSION = '0.5.0' +PKG_VERSION = '0.5.1' PKG_FILES = FileList[ 'lib/**/*.rb', 'Rakefile.rb', diff --git a/lib/cxxproject/buildingblocks/executable.rb b/lib/cxxproject/buildingblocks/executable.rb index 7ffe110..121ef69 100644 --- a/lib/cxxproject/buildingblocks/executable.rb +++ b/lib/cxxproject/buildingblocks/executable.rb @@ -2,7 +2,6 @@ require 'cxxproject/buildingblocks/has_libraries_mixin' require 'cxxproject/buildingblocks/has_sources_mixin' require 'cxxproject/buildingblocks/has_includes_mixin' -require 'cxxproject/utils/process' require 'tmpdir' require 'set' @@ -46,14 +45,14 @@ def linker_libs_string def get_executable_name() # relative path return @exe_name if @exe_name - + parts = [@output_dir] - + if @output_dir_abs parts = [@output_dir_relPath] if @output_dir_relPath parts << 'exes' end - + parts << "#{@name}#{@tcs[:LINKER][:OUTPUT_ENDING]}" @exe_name = File.join(parts) @@ -61,8 +60,8 @@ def get_executable_name() # relative path end def get_task_name() # full path - return @task_name if @task_name - + return @task_name if @task_name + parts = [@output_dir] parts << 'exes' if @output_dir_abs parts << "#{@name}#{@tcs[:LINKER][:OUTPUT_ENDING]}" @@ -70,7 +69,7 @@ def get_task_name() # full path @task_name = @project_dir + "/" + @task_name unless @output_dir_abs @task_name - end + end def collect_unique(array, set) ret = [] @@ -125,37 +124,29 @@ def convert_to_rake() res = typed_file_task Rake::Task::EXECUTABLE, get_task_name => object_multitask do Dir.chdir(@project_dir) do + cmd = remove_empty_strings_and_join([ + linker[:COMMAND], # g++ + linker[:MUST_FLAGS], + linker[:FLAGS], # --all_load + linker[:EXE_FLAG], + get_executable_name, # -o debug/x.exe + get_object_filenames, # debug/src/abc.o debug/src/xy.o + @linker_script ? "#{@tcs[:LINKER][:SCRIPT]} #{@linker_script}" : "", # -T xy/xy.dld + @mapfile ? "#{linker[:MAP_FILE_FLAG]} >#{@output_dir + "/" + @mapfile}" : "", # -Wl,-m6 > xy.map + linker[:LIB_PREFIX_FLAGS], # "-Wl,--whole-archive " + remove_empty_strings_and_join(calc_linker_lib_string), + linker[:LIB_POSTFIX_FLAGS] # "-Wl,--no-whole-archive " + ]) - cmd = [linker[:COMMAND]] # g++ - cmd += linker[:MUST_FLAGS].split(" ") - cmd += linker[:FLAGS].split(" ") # --all_load - cmd << linker[:EXE_FLAG] - cmd << get_executable_name # -o debug/x.exe - cmd += @objects # debug/src/abc.o debug/src/xy.o - cmd << linker[:SCRIPT] if @linker_script # -T - cmd << @linker_script if @linker_script # xy/xy.dld - cmd << linker[:MAP_FILE_FLAG] if @mapfile # -Wl,-m6 - cmd += linker[:LIB_PREFIX_FLAGS].split(" ") # "-Wl,--whole-archive " - cmd += calc_linker_lib_string - cmd += linker[:LIB_POSTFIX_FLAGS].split(" ") # "-Wl,--no-whole-archive " - - rd, wr = IO.pipe - sp = spawn(*cmd, - { - :out=> @mapfile ? "#{@output_dir}/#{@mapfile}" : :err, # > xy.map - :err=>wr - }) - - # for console print - cmd << " >#{@output_dir}/#{@mapfile}" if @mapfile - - consoleOutput = ProcessHelper.readOutput(sp, rd, wr) show_command(cmd, "Linking #{get_executable_name}") + # TempFile used, because some compilers, e.g. diab, uses ">" for piping to map files: + consoleOutput = `#{cmd + " 2>" + get_temp_filename}` + consoleOutput.concat(read_file_or_empty_string(get_temp_filename)) process_console_output(consoleOutput, @tcs[:LINKER][:ERROR_PARSER]) check_system_command(cmd) end end - res.enhance(transitive_config_files) + res.enhance(@config_files) res.enhance([@project_dir + "/" + @linker_script]) if @linker_script add_output_dir_dependency(get_task_name, res, true) @@ -187,5 +178,9 @@ def run_command(task, command) sh "#{command}" end + def get_temp_filename + Dir.tmpdir + "/lake.tmp" + end + end end diff --git a/lib/cxxproject/buildingblocks/has_sources_mixin.rb b/lib/cxxproject/buildingblocks/has_sources_mixin.rb index ad223e5..28cc894 100644 --- a/lib/cxxproject/buildingblocks/has_sources_mixin.rb +++ b/lib/cxxproject/buildingblocks/has_sources_mixin.rb @@ -1,5 +1,4 @@ require 'yaml' -require 'cxxproject/utils/process' module Cxxproject module HasSources @@ -21,14 +20,14 @@ def set_sources(x) @sources = x self end - + def source_patterns @source_patterns ||= [] end def set_source_patterns(x) @source_patterns = x self - end + end def exclude_sources @exclude_sources ||= [] @@ -68,7 +67,7 @@ def calc_compiler_strings() @incArray = local_includes.dup @incArray.concat(includes) - + all_dependencies.each_with_index do |d,i| next if not HasIncludes === d next if i == 0 @@ -76,7 +75,7 @@ def calc_compiler_strings() next if not prefix @incArray.concat(d.includes.map {|inc| File.add_prefix(prefix,inc)}) end - + [:CPP, :C, :ASM].each do |type| @include_string[type] = get_include_string(@tcs, type) @define_string[type] = get_define_string(@tcs, type) @@ -84,11 +83,11 @@ def calc_compiler_strings() end def get_include_string(tcs, type) - @incArray.uniq.map!{|k| "#{tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"} + @incArray.uniq.map!{|k| "#{tcs[:COMPILER][type][:INCLUDE_PATH_FLAG]}#{k}"}.join(" ") end def get_define_string(tcs, type) - tcs[:COMPILER][type][:DEFINES].map {|k| "#{tcs[:COMPILER][type][:DEFINE_FLAG]}#{k}"} + tcs[:COMPILER][type][:DEFINES].map {|k| "#{tcs[:COMPILER][type][:DEFINE_FLAG]}#{k}"}.join(" ") end def get_object_file(sourceRel) @@ -160,7 +159,7 @@ def outfileTask.needed? def create_object_file_tasks() sources_to_build = {} # todo: pair! - + exclude_files = Set.new exclude_sources.each do |p| Dir.glob(p).each {|f| exclude_files << f} @@ -182,13 +181,13 @@ def create_object_file_tasks() sources_to_build[f] = tcs4source(p) end end - + obj_tasks = [] sources_to_build.each do |s, the_tcs| obj_task = create_object_file_task(s, the_tcs) obj_tasks << obj_task unless obj_task.nil? end - + obj_tasks end @@ -203,40 +202,24 @@ def create_object_file_task(sourceRel, the_tcs) @objects << objectRel object = File.expand_path(objectRel) source = File.expand_path(sourceRel) - + depStr = "" - if type != :ASM + if type != :ASM dep_file = get_dep_file(objectRel) depStr = the_tcs[:COMPILER][type][:DEP_FLAGS] + dep_file # -MMD -MF debug/src/abc.o.d end + compiler = the_tcs[:COMPILER][type] + cmd = remove_empty_strings_and_join([compiler[:COMMAND], compiler[:COMPILE_FLAGS], depStr, compiler[:FLAGS], # g++ -c -depstr -g3 + the_tcs == @tcs ? @include_string[type] : get_include_string(the_tcs, type), # -I include + the_tcs == @tcs ? @define_string[type] : get_define_string(the_tcs, type), # -DDEBUG + compiler[:OBJECT_FILE_FLAG], objectRel, sourceRel # -o abc.o src/abc.cpp + ]) res = typed_file_task Rake::Task::OBJECT, object => source do - - i_array = the_tcs == @tcs ? @include_string[type] : get_include_string(the_tcs, type) - d_array = the_tcs == @tcs ? @define_string[type] : get_define_string(the_tcs, type) - - compiler = the_tcs[:COMPILER][type] - cmd = [compiler[:COMMAND]] - cmd += compiler[:COMPILE_FLAGS].split(" ") - cmd += depStr.split(" ") - cmd += compiler[:FLAGS].split(" ") - cmd += i_array - cmd += d_array - cmd << compiler[:OBJECT_FILE_FLAG] - cmd << objectRel - cmd << sourceRel - - rd, wr = IO.pipe - sp = spawn(*cmd, { - :err=>:out, - :out=>wr - }) - consoleOutput = ProcessHelper.readOutput(sp, rd, wr) - show_command(cmd, "Compiling #{sourceRel}") - process_console_output(consoleOutput, compiler[:ERROR_PARSER]) + process_console_output(catch_output(cmd), compiler[:ERROR_PARSER]) check_system_command(cmd) - convert_depfile(dep_file) if type != :ASM + convert_depfile(dep_file) if type != :ASM end enhance_with_additional_files(res) add_output_dir_dependency(object, res, false) @@ -245,8 +228,8 @@ def create_object_file_task(sourceRel, the_tcs) end def enhance_with_additional_files(task) + task.enhance(@config_files) task.enhance(file_dependencies) - task.enhance(transitive_config_files) end def process_console_output(console_output, ep) diff --git a/lib/cxxproject/buildingblocks/source_library.rb b/lib/cxxproject/buildingblocks/source_library.rb index a4eba81..20f96d8 100644 --- a/lib/cxxproject/buildingblocks/source_library.rb +++ b/lib/cxxproject/buildingblocks/source_library.rb @@ -2,7 +2,7 @@ require 'cxxproject/buildingblocks/has_libraries_mixin' require 'cxxproject/buildingblocks/has_sources_mixin' require 'cxxproject/buildingblocks/has_includes_mixin' -require 'cxxproject/utils/process' +require 'cxxproject/utils/string' module Cxxproject class SourceLibrary < BuildingBlock @@ -54,39 +54,53 @@ def get_task_name() # full path # def convert_to_rake() object_multitask = prepare_tasks_for_objects() + archiver = @tcs[:ARCHIVER] res = typed_file_task Rake::Task::LIBRARY, get_task_name => object_multitask do Dir.chdir(@project_dir) do - FileUtils.rm(get_archive_name) if File.exists?(get_archive_name) - cmd = [archiver[:COMMAND]] # ar - cmd += archiver[:ARCHIVE_FLAGS].split(" ") - cmd += archiver[:FLAGS].split(" ") # --all_load - cmd << get_archive_name # -o debug/x.exe - cmd += @objects - - rd, wr = IO.pipe - sp = spawn(*cmd, - { - :err=>:out, - :out=>wr - }) - - consoleOutput = ProcessHelper.readOutput(sp, rd, wr) - + objString = get_object_filenames + if objString.length > 8000 + ar_arrays = StringUtils.splitString(objString,8000,".o ", 1) + archs = [] + for i in 1..ar_arrays.length + cmd = remove_empty_strings_and_join([ + archiver[:COMMAND], # ar + archiver[:ARCHIVE_FLAGS], # -rc + archiver[:FLAGS], + get_archive_name+"_"+i.to_s, # debug/x.a + ar_arrays[i-1] # debug/src/abc.o debug/src/xy.o + ]) + show_command(cmd, "Creating #{get_archive_name}, part #{i} of #{ar_arrays.length}") + process_console_output(catch_output(cmd), @tcs[:ARCHIVER][:ERROR_PARSER]) + check_system_command(cmd) + archs << get_archive_name+"_"+i.to_s + end + objString = archs.join(" ") + end + + cmd = remove_empty_strings_and_join([ + archiver[:COMMAND], # ar + archiver[:ARCHIVE_FLAGS], # -rc + archiver[:FLAGS], + get_archive_name, # debug/x.a + objString # debug/src/abc.o debug/src/xy.o + ]) show_command(cmd, "Creating #{get_archive_name}") - process_console_output(consoleOutput, @tcs[:ARCHIVER][:ERROR_PARSER]) + process_console_output(catch_output(cmd), @tcs[:ARCHIVER][:ERROR_PARSER]) check_system_command(cmd) end end - + enhance_with_additional_files(res) add_output_dir_dependency(get_task_name, res, true) - + add_grouping_tasks(get_task_name) setup_rake_dependencies(res) + + return res end diff --git a/lib/cxxproject/utils/string.rb b/lib/cxxproject/utils/string.rb new file mode 100644 index 0000000..869f32a --- /dev/null +++ b/lib/cxxproject/utils/string.rb @@ -0,0 +1,16 @@ +module Cxxproject + class StringUtils + def self.splitString(str, chunkSize, delim, delimShift = -1) + res = [] + s = str + oldPos = 0 + while s.length > chunkSize + oldPos + pos = s.rindex(delim,oldPos+chunkSize) + res << s[oldPos..pos+delimShift] + oldPos = pos+delim.length + end + res << s[oldPos..-1] + res + end + end +end diff --git a/spec/building_block_spec.rb b/spec/building_block_spec.rb index 8ab614e..8b6ddd6 100644 --- a/spec/building_block_spec.rb +++ b/spec/building_block_spec.rb @@ -45,8 +45,13 @@ end it 'should calc correct transitive_config_files' do - lib1 = Cxxproject::SourceLibrary.new('1').set_config_files(['config1']).set_project_dir('.') - lib2 = Cxxproject::SourceLibrary.new('2').set_dependencies(['1']).set_config_files(['config2']).set_project_dir('.') - lib2.transitive_config_files.should eq(['config2', 'config1']) + lib1 = Cxxproject::SourceLibrary.new('1'). + set_config_files(['config1']). + set_project_dir('.') + lib2 = Cxxproject::SourceLibrary.new('2'). + set_dependencies(['1']). + set_config_files(['config2']). + set_project_dir('.') + Set.new(lib2.transitive_config_files).should eq(Set.new(['config2', 'config1'])) end end