canoe 0.3.3 → 0.3.3.4
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 +4 -4
- data/lib/canoe.rb +3 -12
- data/lib/dependence.rb +25 -30
- data/lib/source_files.rb +9 -13
- data/lib/util.rb +6 -1
- data/lib/workspace/add.rb +1 -0
- data/lib/workspace/build.rb +1 -1
- data/lib/workspace/make.rb +15 -10
- data/lib/workspace/test.rb +35 -27
- data/lib/workspace/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 28de761c23336af9df9ed1117d47f85c22f77abd3030195462d0e43ccba5091c
|
|
4
|
+
data.tar.gz: f0734ecf77c58d6d86a72835fff2e56e1ff49504be3f2ad7cc3e182e550b5623
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff0167eca4be655a4cc33258b5dddfa07e7cbad53d6745b38d75eb301c032403d5338e6249f7704dee460dbaa87a3a4141b8f1ca023abcff5af4a660691b4f2c
|
|
7
|
+
data.tar.gz: f5c494d7cefeefca5e2fd14353f9645479c29f4bb338330ebb9075d103fce73ea678bbb62823053bafdbe3bad497d7b5ecc8a3ca369ff078b937d1e7296e5fbd
|
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 = [
|
|
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/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
|
-
|
|
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
|
-
|
|
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
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
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
|
-
|
|
36
|
-
|
|
37
|
-
|
|
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(
|
|
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
data/lib/workspace/build.rb
CHANGED
|
@@ -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
|
|
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"
|
data/lib/workspace/make.rb
CHANGED
|
@@ -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
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
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
|
-
|
|
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
|
data/lib/workspace/test.rb
CHANGED
|
@@ -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
|
-
ret = deps[file]
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
14
|
+
ret = deps[file].map { |f| f.gsub(".#{@header_suffix}", ".#{@source_suffix}") }
|
|
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
|
-
|
|
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,28 @@ 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
87
|
@compiler.link_executable target, extract_one_file_obj(test_file, deps) + [file_to_obj(test_file)]
|
|
96
88
|
end
|
|
97
89
|
|
|
98
|
-
def build_one_test(test_file, deps)
|
|
99
|
-
|
|
90
|
+
def build_one_test(test_file, deps, indent = "")
|
|
91
|
+
files = DepAnalyzer.compiling_filter(target_deps, Time.new(0), @source_suffix, @header_suffix)
|
|
92
|
+
flag = true
|
|
93
|
+
files << test_file
|
|
94
|
+
|
|
95
|
+
stepper = Stepper.new(files.size, files.size)
|
|
96
|
+
|
|
97
|
+
files.each do |f|
|
|
98
|
+
o = file_to_obj(f)
|
|
99
|
+
printf "#{indent}#{stepper.progress_as_str.green} compiling #{f.yellow}: "
|
|
100
|
+
flag &= compile f, o
|
|
101
|
+
stepper.step
|
|
102
|
+
end
|
|
103
|
+
abort_on_err("Compiling errors encountered") unless flag;
|
|
104
|
+
|
|
105
|
+
printf "#{indent}#{stepper.progress_as_str.green} compiling finished\n"
|
|
106
|
+
puts "#{indent}[100%]".green + " linking"
|
|
100
107
|
link_one_test(test_file, deps)
|
|
101
108
|
end
|
|
102
109
|
|
|
@@ -108,8 +115,8 @@ module Canoe
|
|
|
108
115
|
stepper = Stepper.new fetch_all_test_files.size, files.size
|
|
109
116
|
|
|
110
117
|
files.each do |f|
|
|
111
|
-
printf "#{stepper.progress_as_str.green}
|
|
112
|
-
|
|
118
|
+
printf "#{stepper.progress_as_str.green} building #{File.basename(f, "." + @source_suffix).yellow}:\n"
|
|
119
|
+
build_one_test(f, deps, " ")
|
|
113
120
|
stepper.step
|
|
114
121
|
end
|
|
115
122
|
end
|
|
@@ -126,6 +133,7 @@ module Canoe
|
|
|
126
133
|
end
|
|
127
134
|
|
|
128
135
|
def build_test
|
|
136
|
+
build_compiler_from_config
|
|
129
137
|
puts "#{'[COMPILING TESTS]'.magenta}..."
|
|
130
138
|
return unless test_build_time
|
|
131
139
|
|
data/lib/workspace/version.rb
CHANGED
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
|
|
4
|
+
version: 0.3.3.4
|
|
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-
|
|
11
|
+
date: 2021-12-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.
|