canoe 0.3.3.1 → 0.3.3.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: f306cd1daca6a05e5ed98b6bac0d638ee6c8b3deb8f033573254b40e0e111f04
4
- data.tar.gz: 20025070fa9b8880e7702fa1560458c6c02f3bd6ef544f0c105c04c4eabbb08b
3
+ metadata.gz: a3111ef55f0ad1370cff694b437b63ae49dce9f59347e3b70dab2e5abecabd32
4
+ data.tar.gz: 97a41a1bf0f2cd914398db463bcafa05705ddf3b6a1987e815a9cc306b4a3d14
5
5
  SHA512:
6
- metadata.gz: 57d280fbde673916e1abc93a027cb9be3eda421a9bf9e65ece2c5415d9c0be19236070575b464b09d934aad7729343afcbd9e105424105417e1ea14db50e300c
7
- data.tar.gz: b0724750762fe724958ec732e7f701d13f8b0d7c2cfaf80f8e32c01e959b982e682594cc543cc45115e0aef0a70bfd93c0ca53cd48aa8278b905d87904f52ad7
6
+ metadata.gz: 81c885681b3c65a638915922df7ad598b90d206c3c988f35b0ac685d648634288e4cfe67094fc53c91b6a691c241cc1097c0da4e2794f75511b502af92290636
7
+ data.tar.gz: f4813ff8c8f3150fd1108a7a3bdf4db809d108c4b519fed546532d1a314bfc811ec2fa4e297f0a1ae83ff94d27a184292aa8df2986e2d82b3a3a93dafb4a2773
data/lib/canoe.rb CHANGED
@@ -3,20 +3,11 @@ require_relative 'cmd'
3
3
  require_relative 'source_files'
4
4
 
5
5
  module Canoe
6
+ ##
7
+ # Main class for building a canoe project
6
8
  class Builder
7
9
  def initialize
8
- options = ['new',
9
- 'add',
10
- 'build',
11
- 'generate',
12
- 'make',
13
- 'run',
14
- 'dep',
15
- 'clean',
16
- 'version',
17
- 'help',
18
- 'update',
19
- 'test']
10
+ options = %w[new add build generate make run dep clean version help update test]
20
11
  @cmd = CmdParser.new options
21
12
  end
22
13
 
data/lib/coloring.rb CHANGED
@@ -10,7 +10,7 @@ class String
10
10
  34 => :blue,
11
11
  35 => :magenta,
12
12
  36 => :cyan,
13
- 37 => :white,
13
+ 37 => :white
14
14
  }
15
15
  colors.each do |k, v|
16
16
  define_method v do
data/lib/dependence.rb CHANGED
@@ -1,24 +1,23 @@
1
1
  require_relative 'source_files'
2
2
  require_relative 'util'
3
- ##
4
- # class DepAnalyzer
5
- # This class is the key component of canoe, which offers file dependency analysis functionality.
6
- # A DepAnalyzer takes a directory as input, sources files and corresponding header files in this
7
- # directory should have same name, e.g. test.cpp and test.hpp.
8
- # DepAnalyzer would read every source file and recursively process user header files included in this source file to
9
- # find out all user header files this source file depends on.
10
- # Based on dependencies built in previous stage, DepAnalyzer determines which files should be recompiled and return
11
- # these files to caller.
12
- #
13
- # Dependencies could be written to a file to avoid wasting time parsing all files, Depanalyzer would read from
14
- # this file to construct dependencies. But if sources files included new headers or included headers are revmoed,
15
- # Depanalyzer should rebuild the whole dependencies.
16
3
  module Canoe
4
+ ##
5
+ # This class is the key component of canoe, which offers file dependency analysis functionality.
6
+ #
7
+ # A DepAnalyzer takes a directory as input, sources files and corresponding header files in this
8
+ # directory should have same name, e.g. test.cpp and test.hpp. DepAnalyzer would read every source file and
9
+ # recursively process user header files included in this source file to find out all user header files this
10
+ # source file depends on. Based on dependencies built in previous stage, DepAnalyzer determines which files
11
+ # should be recompiled and return these files to caller. Dependencies could be written to a file to avoid
12
+ # wasting time parsing all files, Depanalyzer would read from this file to construct dependencies. But if
13
+ # sources files included new headers or included headers are revmoed, Depanalyzer should rebuild the whole
14
+ # dependencies.
17
15
  class DepAnalyzer
18
16
  include Err
19
17
  include SystemCommand
20
18
 
21
19
  class << self
20
+ include Err
22
21
  include WorkSpaceUtil
23
22
  def read_from(filename)
24
23
  File.open(filename, 'r') do |f|
@@ -34,29 +33,28 @@ module Canoe
34
33
 
35
34
  def compiling_filter(deps, build_time, src_sfx = 'cpp', hdr_sfx = 'hpp')
36
35
  files = []
37
- @processed = {}
38
36
  @recompiles = {}
39
37
  deps.each_key do |k|
40
- @processed[k] = false
41
38
  @recompiles[k] = false
42
39
  end
43
40
  deps.each do |k, v|
44
41
  next if k.end_with? ".#{hdr_sfx}"
45
42
 
46
- if should_recompile?(k, build_time)
47
- files << k
48
- @processed[k] = true
49
- @recompiles[k] = true
50
- next
51
- end
43
+ # first analyze dependency to discover circular includes
52
44
  v.each do |f|
53
45
  next unless mark(f, build_time, deps) || mark(f.sub(".#{hdr_sfx}", ".#{src_sfx}"), build_time, deps)
54
46
 
55
47
  files << k
56
- @processed[k] = true
57
48
  @recompiles[k] = true
58
49
  break
59
50
  end
51
+
52
+ next if @recompiles[k]
53
+
54
+ if should_recompile?(k, build_time)
55
+ files << k
56
+ @recompiles[k] = true
57
+ end
60
58
  end
61
59
  files
62
60
  end
@@ -64,22 +62,19 @@ module Canoe
64
62
  private
65
63
 
66
64
  def mark(file, build_time, deps)
67
- ret = false
68
65
  return false unless File.exist? file
69
- return true if should_recompile?(file, build_time)
70
66
 
67
+ # first analyze dependency to discover circular includes
71
68
  deps[file].each do |f|
72
- if @processed[f]
73
- ret |= @recompiles[f]
74
- next
75
- end
76
- @processed[f] = true
77
69
  if mark(f, build_time, deps)
78
70
  @recompiles[f] = true
79
71
  return true
80
72
  end
73
+ rescue SystemStackError
74
+ puts "#{"Fatal: ".red}file #{file} is circularly included"
75
+ exit false
81
76
  end
82
- ret
77
+ true if should_recompile?(file, build_time)
83
78
  end
84
79
 
85
80
  def should_recompile?(file, build_time)
data/lib/source_files.rb CHANGED
@@ -13,13 +13,11 @@ class SourceFiles
13
13
  @files = []
14
14
  Dir.each_child(dir) do |f|
15
15
  file = "#{dir}/#{f}"
16
- if File.file? file
17
- if block_given?
18
- @files << file.to_s if yield(f)
19
- else
20
- @files << file.to_s
21
- end
22
- end
16
+ next unless File.file?(file)
17
+
18
+ add = true
19
+ add = yield(f) if block_given?
20
+ @files << file.to_s if add
23
21
  end
24
22
 
25
23
  @files
@@ -32,13 +30,11 @@ class SourceFiles
32
30
  file = "#{dir}/#{f}"
33
31
  # we don't handle symlinks
34
32
  if File.file? file
35
- if block_given?
36
- @files << "#{file}" if yield(f)
37
- else
38
- @files << "#{file}"
39
- end
33
+ add = true
34
+ add = yield(f) if block_given?
35
+ @files << file if add
40
36
  elsif File.directory? file
41
- get_all_helper("#{file}", &block)
37
+ get_all_helper(file, &block)
42
38
  end
43
39
  end
44
40
  end
data/lib/util.rb CHANGED
@@ -1,3 +1,4 @@
1
+ # Many useful classes to record compiling progress, change file's name and issueing system commands
1
2
  require_relative 'coloring'
2
3
 
3
4
  require 'English'
@@ -59,6 +60,8 @@ module Canoe
59
60
  end
60
61
  end
61
62
 
63
+ ##
64
+ # issueing system commands by accepting a command string
62
65
  module SystemCommand
63
66
  def issue_command(cmd_str)
64
67
  puts cmd_str
@@ -72,7 +75,9 @@ module Canoe
72
75
  status
73
76
  end
74
77
  end
75
-
78
+
79
+ ##
80
+ # Colorized error messages with abortion
76
81
  module Err
77
82
  def warn_on_err(err)
78
83
  puts <<~ERR
data/lib/workspace/add.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  module Canoe
2
+ # WorkSpace implementation
2
3
  class WorkSpace
3
4
  def add(args)
4
5
  args.each do |i|
@@ -135,7 +135,7 @@ module Canoe
135
135
  puts "#{'[BUILDING TARGET]'.magenta}..."
136
136
  target = "#{@target}/#{@name}"
137
137
  build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
138
- files = DepAnalyzer.compiling_filter target_deps, build_time, @source_suffix, @header_suffix
138
+ files = DepAnalyzer.compiling_filter(target_deps, build_time, @source_suffix, @header_suffix)
139
139
 
140
140
  if files.empty? && File.exist?(target)
141
141
  puts "nothing to do, all up to date"
@@ -84,7 +84,7 @@ module Canoe
84
84
  def define_variables(makefile, deps)
85
85
  define_dirs(makefile)
86
86
  src_files = deps.keys.select { |f| f.end_with? get_source_suffix }
87
-
87
+
88
88
  generate_all_names(src_files)
89
89
  define_srcs(makefile, src_files)
90
90
  makefile.puts ''
@@ -163,15 +163,20 @@ module Canoe
163
163
  end
164
164
 
165
165
  def get_all_dep_name(file_name, deps)
166
- dep = deps[file_name]
167
- if dep.empty?
168
- []
169
- else
170
- tmp = dep.map { |n| extract_name(n, @workspace.components_prefix).upcase }
171
- dep.each do |d|
172
- tmp += get_all_dep_name(d, deps)
166
+ begin
167
+ dep = deps[file_name]
168
+ if dep.empty?
169
+ []
170
+ else
171
+ tmp = dep.map { |n| extract_name(n, @workspace.components_prefix).upcase }
172
+ dep.each do |d|
173
+ tmp += get_all_dep_name(d, deps)
174
+ end
175
+ tmp
173
176
  end
174
- tmp
177
+ rescue SystemStackError
178
+ puts "#{"Fatal: ".red}file #{file_name} is circularly included"
179
+ exit false
175
180
  end
176
181
  end
177
182
 
@@ -246,7 +251,7 @@ module Canoe
246
251
  def make_clean(makefile)
247
252
  clean = <<~DOC
248
253
  .PHONY: clean
249
- clean:
254
+ clean:
250
255
  \trm ./target/*
251
256
  \trm ./obj/*.o
252
257
  DOC
@@ -8,17 +8,21 @@ module Canoe
8
8
  # we don't handle spaces
9
9
  test_single(args[0], args[1..].join(" "))
10
10
  end
11
-
11
+
12
12
  # extract one test file's dependency
13
13
  def extract_one_file(file, deps)
14
14
  ret = deps[file].map { |f| f.gsub(".#{@header_suffix}", ".#{@source_suffix}") }
15
-
16
- deps[file].each do |f|
17
- dep = extract_one_file(f, deps)
18
- dep.each do |d|
19
- ret << d unless ret.include?(d)
15
+ begin
16
+ deps[file].each do |f|
17
+ dep = extract_one_file(f, deps)
18
+ dep.each do |d|
19
+ ret << d unless ret.include?(d)
20
+ end
20
21
  end
21
- end
22
+ rescue SystemStackError
23
+ puts "#{"Fatal: ".red}file #{file} is circularly included"
24
+ exit false
25
+ end
22
26
  ret.map { |f| f.gsub(".#{@header_suffix}", ".#{@source_suffix}") }
23
27
  end
24
28
 
@@ -42,10 +46,11 @@ module Canoe
42
46
  bin = "#{@target_short}/test_#{name}"
43
47
 
44
48
  rebuild ||= !File.exist?(bin)
45
-
49
+
46
50
  file = "#{@tests_short}/test_#{name}.#{@source_suffix}"
51
+ abort_on_err "No test file exists for #{name}" unless File.exist?(file)
47
52
  rebuild ||= File.mtime(bin) < File.mtime(file)
48
-
53
+
49
54
  deps = fetch_all_deps
50
55
  extract_one_file(file, deps).each do |f|
51
56
  rebuild ||= File.mtime(bin) < File.mtime(f) || File.mtime(bin) < File.mtime(hdr_of_src(f))
@@ -77,26 +82,29 @@ module Canoe
77
82
  end.min
78
83
  end
79
84
 
80
- # @deps is the dependency hash for tests
81
- # cyclic dependency is not handled
82
- # compiler should first be built
83
- def compile_one_test(test_file, deps)
84
- extract_one_file(test_file, deps).each do |f|
85
- o = file_to_obj(f)
86
- next if File.exist?(o) && File.mtime(o) > File.mtime(f) && File.mtime(o) > File.mtime(hdr_of_src(f))
87
-
88
- compile(f, o)
89
- end
90
- compile(test_file, file_to_obj(test_file))
91
- end
92
-
93
85
  def link_one_test(test_file, deps)
94
86
  target = "#{@target_short}/#{File.basename(test_file, '.*')}"
95
- @compiler.link_executable target, extract_one_file_obj(test_file, deps) + [file_to_obj(test_file)]
87
+ all_objs = Dir.glob("obj/*.o").reject { |f| f.start_with?('obj/test_') || f == 'obj/main.o'}
88
+ @compiler.link_executable target, all_objs + [file_to_obj(test_file)]
96
89
  end
97
90
 
98
- def build_one_test(test_file, deps)
99
- compile_one_test(test_file, deps)
91
+ def build_one_test(test_file, deps, indent = "")
92
+ files = DepAnalyzer.compiling_filter(target_deps, Time.new(0), @source_suffix, @header_suffix)
93
+ flag = true
94
+ files << test_file
95
+
96
+ stepper = Stepper.new(files.size, files.size)
97
+
98
+ files.each do |f|
99
+ o = file_to_obj(f)
100
+ printf "#{indent}#{stepper.progress_as_str.green} compiling #{f.yellow}: "
101
+ flag &= compile f, o
102
+ stepper.step
103
+ end
104
+ abort_on_err("Compiling errors encountered") unless flag;
105
+
106
+ printf "#{indent}#{stepper.progress_as_str.green} compiling finished\n"
107
+ puts "#{indent}[100%]".green + " linking"
100
108
  link_one_test(test_file, deps)
101
109
  end
102
110
 
@@ -108,8 +116,8 @@ module Canoe
108
116
  stepper = Stepper.new fetch_all_test_files.size, files.size
109
117
 
110
118
  files.each do |f|
111
- printf "#{stepper.progress_as_str.green} compiling #{f} "
112
- compile_one_test(f, deps)
119
+ printf "#{stepper.progress_as_str.green} building #{File.basename(f, "." + @source_suffix).yellow}:\n"
120
+ build_one_test(f, deps, " ")
113
121
  stepper.step
114
122
  end
115
123
  end
@@ -126,6 +134,7 @@ module Canoe
126
134
  end
127
135
 
128
136
  def build_test
137
+ build_compiler_from_config
129
138
  puts "#{'[COMPILING TESTS]'.magenta}..."
130
139
  return unless test_build_time
131
140
 
@@ -2,7 +2,7 @@ module Canoe
2
2
  class WorkSpace
3
3
  def self.version
4
4
  puts <<~VER
5
- canoe v0.3.3.1
5
+ canoe v0.3.3.5
6
6
  For features in this version, please visit https://github.com/Dicridon/canoe
7
7
  Currently, canoe can do below:
8
8
  - project creation
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: canoe
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.3.3.1
4
+ version: 0.3.3.5
5
5
  platform: ruby
6
6
  authors:
7
7
  - XIONG Ziwei
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-18 00:00:00.000000000 Z
11
+ date: 2022-02-19 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |+
14
14
  Canoe offers project management and building facilities to C/C++ projects.