canoe 0.3.1.1 → 0.3.2

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.
@@ -1,27 +1,36 @@
1
- class WorkSpace
2
- def clean
3
- self.send "clean_#{@mode.to_s}"
4
- end
1
+ module Canoe
2
+ class WorkSpace
3
+ # valid options: none, 'all', 'target', 'tests'
4
+ def clean(args)
5
+ options = {
6
+ [] => 'all', ['all'] => 'all',
7
+ ['target'] => 'target', ['tests'] => 'tests', ['obj'] => 'obj'
8
+ }
9
+ if options.include?(args)
10
+ send "clean_#{options[args]}"
11
+ else
12
+ abort_on_err "Unkown subcommand #{args.join(' ').red}"
13
+ end
14
+ end
5
15
 
6
- private
16
+ private
7
17
 
8
- def clean_obj
9
- puts "rm -f ./obj/*.o"
10
- system "rm -f ./obj/*.o"
11
- end
18
+ def clean_all
19
+ clean_target
20
+ clean_obj
21
+ end
12
22
 
13
- def clean_target
14
- puts "rm -f ./target/*"
15
- system "rm -f ./target/*"
16
- end
23
+ def clean_target
24
+ issue_command 'rm ./target/* -rf'
25
+ end
17
26
 
18
- def clean_bin
19
- clean_obj
20
- clean_target
21
- end
27
+ def clean_obj
28
+ issue_command 'rm ./obj/* -rf'
29
+ end
22
30
 
23
- def clean_lib
24
- clean_obj
25
- clean_target
31
+ def clean_tests
32
+ issue_command 'rm ./obj/test_* -rf'
33
+ issue_command 'rm ./target/test_* -rf'
34
+ end
26
35
  end
27
36
  end
data/lib/workspace/dep.rb CHANGED
@@ -1,11 +1,13 @@
1
- class WorkSpace
2
- def dep
3
- deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
4
- deps.each do |k, v|
5
- unless v.empty?
1
+ module Canoe
2
+ class WorkSpace
3
+ def dep
4
+ deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
5
+ deps.each do |k, v|
6
+ next if v.empty?
7
+
6
8
  puts "#{k.blue} depends on: "
7
9
  v.each { |f| puts " #{f.blue}" }
8
- puts ""
10
+ puts ''
9
11
  end
10
12
  end
11
13
  end
@@ -1,5 +1,10 @@
1
- class WorkSpace
2
- def generate
3
- DepAnalyzer.new("./src", @source_suffix, @header_suffix).build_to_file ["./src", "./src/components"], @deps
1
+ module Canoe
2
+ class WorkSpace
3
+ def generate
4
+ DepAnalyzer.new(@src_short, @source_suffix, @header_suffix)
5
+ .build_to_file [@src_short, @components_short], @deps
6
+ DepAnalyzer.new(@tests_short, @source_suffix, @header_suffix)
7
+ .build_to_file [@src_short, @components_short], @test_deps
8
+ end
4
9
  end
5
10
  end
@@ -1,11 +1,14 @@
1
- class WorkSpace
2
- def self.help
3
- info = <<~INFO
1
+ module Canoe
2
+ class WorkSpace
3
+ def self.help
4
+ info = <<~INFO
4
5
  canoe is a C/C++ project manager, inspired by Rust cargo.
5
6
  usage:
6
7
  canoe new tada: create a project named 'tada' in current directory
7
8
 
8
9
  canoe build: compile current project (execute this command in project directory)
10
+
11
+ canoe test: build and run tests
9
12
 
10
13
  canoe generate: generate dependency relationships and store it in '.canoe.deps' file. Alias: update
11
14
 
@@ -47,8 +50,12 @@ class WorkSpace
47
50
  So when a file includes new headers or some headers are removed, users have to use 'canoe udpate'
48
51
  to update dependency relationships.
49
52
 
50
- build [options]:
51
- build current project, arguments in [options] will be passed to C++ compiler
53
+ build [all|test]:
54
+ build current project, 'all' builds both target and tests, 'test' builds tests only
55
+
56
+ test [tests]:
57
+ build and run tests
58
+ [tests]: 'all' for all tests, or a name of a test for a single test
52
59
 
53
60
  run [options]:
54
61
  build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
@@ -71,6 +78,7 @@ class WorkSpace
71
78
  @author: written by XIONG Ziwei, ICT, CAS
72
79
  @contact: noahxiong@outlook.com
73
80
  INFO
74
- puts info
81
+ puts info
82
+ end
75
83
  end
76
84
  end
@@ -1,233 +1,280 @@
1
1
  # If the project has circular dependency, this command would fail
2
- class Makefile
3
- def initialize(workspace)
4
- @workspace = workspace
5
- @all_names = []
6
- @common_variables = {}
7
- @src_variables = {}
8
- @hdr_variables = {}
9
- @obj_variables = {}
10
- @config = {}
11
- end
2
+ module Canoe
3
+ class Makefile
4
+ include WorkSpaceUtil
5
+ def initialize(workspace)
6
+ @workspace = workspace
7
+ @all_names = []
8
+ @common_variables = {}
9
+ @src_variables = {}
10
+ @hdr_variables = {}
11
+ @obj_variables = {}
12
+ @config = {}
13
+ end
12
14
 
13
- def configure(config)
14
- @config = config
15
- end
15
+ def configure(config)
16
+ @config = config
17
+ end
16
18
 
17
- def make!(deps)
18
- File.open("Makefile", "w") do |f|
19
- if cxx?(get_compiler)
20
- make_cxx(f, deps)
21
- else
22
- make_c(f, deps)
19
+ def make!(deps)
20
+ File.open('Makefile', 'w') do |f|
21
+ if cxx?(get_compiler)
22
+ make_cxx(f, deps)
23
+ else
24
+ make_c(f, deps)
25
+ end
23
26
  end
24
27
  end
25
- end
26
28
 
27
- private
29
+ private
28
30
 
29
- def get_compiler
30
- @config["compiler"]
31
- end
31
+ def get_compiler
32
+ @config['compiler']
33
+ end
32
34
 
33
- def get_header_suffix
34
- @workspace.header_suffix
35
- end
35
+ def get_header_suffix
36
+ @workspace.header_suffix
37
+ end
36
38
 
37
- def get_source_suffix
38
- @workspace.source_suffix
39
- end
39
+ def get_source_suffix
40
+ @workspace.source_suffix
41
+ end
40
42
 
41
- def get_compiling_flags
42
- flags = @config["flags"]["compile"].values.join " "
43
- flags + " -I./src/components"
44
- end
43
+ def get_compiling_flags
44
+ flags = @config['flags']['compile'].values.join ' '
45
+ flags + ' -I./src/components'
46
+ end
45
47
 
46
- def get_ldflags
47
- @config["flags"]["link"].values.select { |v| v.start_with?("-L") }.join " "
48
- end
48
+ def get_ldflags
49
+ @config['flags']['link'].values.select { |v| v.start_with?('-L') }.join ' '
50
+ end
49
51
 
50
- def get_ldlibs
51
- (@config["flags"]["link"].values - (get_ldflags.split)).join " "
52
- end
52
+ def get_ldlibs
53
+ (@config['flags']['link'].values - (get_ldflags.split)).join ' '
54
+ end
53
55
 
54
- def cxx?(name)
55
- return get_compiler.end_with? "++"
56
- end
56
+ def cxx?(name)
57
+ return get_compiler.end_with? '++'
58
+ end
57
59
 
58
- def make_cxx(makefile, deps)
59
- make_common(makefile, "CXX", deps)
60
- end
60
+ def make_cxx(makefile, deps)
61
+ make_common(makefile, 'CXX', deps)
62
+ end
61
63
 
62
- def make_c(makefile, deps)
63
- make_common(makefile, "CC", deps)
64
- end
64
+ def make_c(makefile, deps)
65
+ make_common(makefile, 'CC', deps)
66
+ end
65
67
 
66
- def make_common(makefile, compiler_prefix, deps)
67
- make_compiling_info(makefile, compiler_prefix)
68
- define_variables(makefile, deps)
69
- make_rules(makefile, deps)
70
- end
68
+ def make_common(makefile, compiler_prefix, deps)
69
+ make_compiling_info(makefile, compiler_prefix)
70
+ define_variables(makefile, deps)
71
+ make_rules(makefile, deps)
72
+ end
71
73
 
72
- def make_compiling_info(makefile, compiler_prefix)
73
- makefile.puts("#{compiler_prefix}=#{get_compiler}")
74
- makefile.puts("#{compiler_prefix}FLAGS=#{get_compiling_flags}")
75
- makefile.puts("LDFLAGS=#{get_ldflags}")
76
- makefile.puts("LDLIBS=#{get_ldlibs}")
77
- makefile.puts ""
78
- end
74
+ def make_compiling_info(makefile, compiler_prefix)
75
+ makefile.puts("#{compiler_prefix}=#{get_compiler}")
76
+ makefile.puts("#{compiler_prefix}FLAGS=#{get_compiling_flags}")
77
+ makefile.puts("LDFLAGS=#{get_ldflags}")
78
+ makefile.puts("LDLIBS=#{get_ldlibs}")
79
+ makefile.puts ''
80
+ end
79
81
 
80
- def define_variables(makefile, deps)
81
- define_dirs(makefile)
82
-
83
- src_files = deps.keys.select { |f| f.end_with? get_source_suffix }
84
- generate_all_names(src_files)
85
- define_srcs(makefile, src_files)
86
- makefile.puts ""
87
- define_hdrs(makefile, src_files)
88
- makefile.puts ""
89
- define_objs(makefile, src_files)
90
- makefile.puts ""
91
- end
82
+ def define_variables(makefile, deps)
83
+ define_dirs(makefile)
84
+ src_files = deps.keys.select { |f| f.end_with? get_source_suffix }
85
+
86
+ generate_all_names(src_files)
87
+ define_srcs(makefile, src_files)
88
+ makefile.puts ''
89
+ define_hdrs(makefile, src_files)
90
+ makefile.puts ''
91
+ define_objs(makefile, src_files)
92
+ makefile.puts ''
93
+ define_tests(makefile, src_files)
94
+ makefile.puts ''
95
+ end
92
96
 
93
- def extract_name(name, prefix)
94
- if name.start_with?(prefix)
95
- name.delete_suffix(File.extname(name))[prefix.length..].gsub("/", "_")
96
- else
97
- File.basename(name.split("/")[-1], ".*")
97
+ def extract_name(name, _)
98
+ File.basename(file_to_obj(name), '.*')
98
99
  end
99
- end
100
100
 
101
- def generate_all_names(files)
102
- files.each do |f|
103
- name = extract_name(f, @workspace.components_prefix).upcase
104
- @all_names << name
105
- @src_variables[name] = f
106
- @hdr_variables[name] = f.gsub(@workspace.source_suffix, @workspace.header_suffix)
107
- @obj_variables[name] = @workspace.obj_prefix + extract_name(f, @workspace.components_prefix) + ".o"
101
+ def generate_all_names(files)
102
+ files.each do |f|
103
+ name = extract_name(f, @workspace.components_prefix).upcase
104
+ @all_names << name
105
+ @src_variables[name] = f
106
+ @hdr_variables[name] = f.gsub @workspace.source_suffix, @workspace.header_suffix
107
+ @obj_variables[name] = file_to_obj(f)
108
+ end
108
109
  end
109
- end
110
110
 
111
- def define_dirs(makefile)
112
- makefile.puts("TARGET_DIR=./target")
113
- if @workspace.mode == :bin
114
- makefile.puts("TARGET=$(TARGET_DIR)/#{@workspace.name}")
115
- else
116
- makefile.puts("TARGET=$(TARGET_DIR)/lib#{@workspace.name.downcase}.so")
117
- end
118
- # note the ending slash
119
- makefile.puts("OBJ_DIR=#{@workspace.obj_prefix[..-2]}")
120
- makefile.puts("SRC_DIR=#{@workspace.src_prefix[..-2]}")
121
- makefile.puts("COMPONENTS_DIR=#{@workspace.components_prefix[..-2]}")
122
- makefile.puts ""
123
- end
111
+ def define_dirs(makefile)
112
+ makefile.puts("TARGET_DIR=./target")
113
+ if @workspace.mode == :bin
114
+ makefile.puts("TARGET=$(TARGET_DIR)/#{@workspace.name}")
115
+ else
116
+ makefile.puts("TARGET=$(TARGET_DIR)/lib#{@workspace.name.downcase}.so")
117
+ end
118
+ # note the ending slash
119
+ makefile.puts("OBJ_DIR=#{@workspace.obj_prefix[..-2]}")
120
+ makefile.puts("SRC_DIR=#{@workspace.src_prefix[..-2]}")
121
+ makefile.puts("COMPONENTS_DIR=#{@workspace.components_prefix[..-2]}")
122
+ makefile.puts ""
123
+ end
124
124
 
125
- def define_srcs(makefile, files)
126
- @src_variables.each do |k, v|
127
- makefile.puts("SRC_#{k}=#{v}")
125
+ def define_srcs(makefile, files)
126
+ @src_variables.each do |k, v|
127
+ makefile.puts("SRC_#{k}=#{v}")
128
+ end
128
129
  end
129
- end
130
130
 
131
- def define_hdrs(makefile, files)
132
- @hdr_variables.each do |k, v|
133
- next if k == "MAIN"
134
- makefile.puts("HDR_#{k}=#{v}")
131
+ def define_hdrs(makefile, files)
132
+ @hdr_variables.each do |k, v|
133
+ next if k == "MAIN"
134
+ makefile.puts("HDR_#{k}=#{v}") if File.exist? v
135
+ end
135
136
  end
136
- end
137
137
 
138
- def define_objs(makefile, files)
139
- @obj_variables.each do |k, v|
140
- makefile.puts("OBJ_#{k}=#{v}")
138
+ def define_objs(makefile, files)
139
+ @obj_variables.each do |k, v|
140
+ makefile.puts("OBJ_#{k}=#{v}")
141
+ end
142
+ objs = @obj_variables.keys.map { |k| "$(OBJ_#{k})" }
143
+ bin_objs = objs.reject { |o| o.start_with? '$(OBJ_TEST'}
144
+ test_objs = objs - bin_objs
145
+ makefile.puts ''
146
+ makefile.puts("OUT_OBJS=#{bin_objs.join ' '}")
147
+ makefile.puts("TEST_OBJS=#{test_objs.join ' '}")
141
148
  end
142
- objs = @obj_variables.keys.map { |k| "$(OBJ_#{k})" }.join " "
143
- makefile.puts("OBJS=#{objs}")
144
- makefile.puts ""
145
- end
146
149
 
147
- def get_all_dep_name(file_name, deps)
148
- dep = deps[file_name]
149
- if dep.empty?
150
- []
151
- else
152
- tmp = dep.map { |n| extract_name(n, @workspace.components_prefix).upcase }
153
- dep.each do |d|
154
- tmp += get_all_dep_name(d, deps)
150
+ def define_tests(makefile, files)
151
+ test_files = files.select { |f| File.basename(f, '.*').start_with? 'test_'}
152
+ test_files.each do |f|
153
+ basename = File.basename(f, '.*')
154
+ test = "#{@workspace.target_short}/#{basename}"
155
+ makefile.puts("#{basename.upcase}=#{test}")
156
+ end
157
+ tests = test_files.map do |f|
158
+ "$(#{File.basename(f, '.*').upcase})"
155
159
  end
156
- tmp
160
+ makefile.puts("TESTS=#{tests.join ' '}")
157
161
  end
158
- end
159
162
 
160
- def emit_dependencies(makefile, name, deps)
161
- as_str = deps.map do |n|
162
- if n == name
163
- ["$(SRC_#{n})"] + ["$(HDR_#{n})"] * (name == "MAIN" ? 0 : 1)
163
+ def get_all_dep_name(file_name, deps)
164
+ dep = deps[file_name]
165
+ if dep.empty?
166
+ []
164
167
  else
165
- "$(#{n}_DEP)"
168
+ tmp = dep.map { |n| extract_name(n, @workspace.components_prefix).upcase }
169
+ dep.each do |d|
170
+ tmp += get_all_dep_name(d, deps)
171
+ end
172
+ tmp
173
+ end
174
+ end
175
+
176
+ def emit_dependencies(makefile, name, deps)
177
+ as_str = deps.map do |n|
178
+ if n == name
179
+ ["$(SRC_#{n})"] + ["$(HDR_#{n})"] * (name == "MAIN" ? 0 : 1)
180
+ else
181
+ "$(#{n}_DEP)"
182
+ end
183
+ end.flatten.join " "
184
+ makefile.puts("#{name}_DEP=#{as_str}")
185
+ end
186
+
187
+ def make_dependencies(makefile, deps)
188
+ dep_variables = Hash[@all_names.map { |n| [n, []] }]
189
+ reference = Hash[@all_names.map { |n| [n, []] }]
190
+ @all_names.each do |n|
191
+ dep_variables[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
192
+ reference[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
193
+ end
194
+
195
+ # deduplication
196
+ dep_variables.each do |k, v|
197
+ v.each do |n|
198
+ next if n == k
199
+ v = v - reference[n] + [n] if v.include? n
200
+ end
201
+ dep_variables[k] = v
166
202
  end
167
- end.flatten.join " "
168
- makefile.puts("#{name}_DEP=#{as_str}")
169
- end
170
203
 
171
- def make_dependencies(makefile, deps)
172
- dep_variables = Hash[@all_names.map { |n| [n, []] }]
173
- reference = Hash[@all_names.map { |n| [n, []] }]
174
- @all_names.each do |n|
175
- dep_variables[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
176
- reference[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
204
+ dep_variables.each do |k, v|
205
+ emit_dependencies(makefile, k, v)
206
+ end
177
207
  end
178
208
 
179
- # deduplication
180
- dep_variables.each do |k, v|
181
- v.each do |n|
182
- next if n == k
183
- v = v - reference[n] + [n] if v.include? n
209
+ def make_obj_rules(makefile, deps)
210
+ cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
211
+ makefile.puts("all: OUT\n")
212
+ makefile.puts ''
213
+
214
+ @all_names.each do |n|
215
+ makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $@ -c $(SRC_#{n})")
216
+ makefile.puts ''
184
217
  end
185
- dep_variables[k] = v
218
+
186
219
  end
187
220
 
188
- dep_variables.each do |k, v|
189
- emit_dependencies(makefile, k, v)
221
+ def make_out_rules(makefile, deps)
222
+ cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
223
+ if @workspace.mode == :bin
224
+ makefile.puts("OUT: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(OUT_OBJS) $(LDFLAGS) $(LDLIBS)")
225
+ else
226
+ makefile.puts("OUT: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -shared -o $(TARGET) $(OUT_OBJS) -fPIC $(LDFLAGS) $(LDLIBS)")
227
+ end
228
+ makefile.puts ''
229
+ makefile.puts("test: $(TESTS)")
190
230
  end
191
- end
192
231
 
193
- def make_rules(makefile, deps)
194
- make_dependencies(makefile, deps)
195
- makefile.puts ""
196
- makefile.puts("all: BIN\n")
197
- makefile.puts ""
198
- cmplr = cxx?(get_compiler) ? "CXX" : "CC"
199
- @all_names.each do |n|
200
- makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(OBJ_#{n}) -c $(SRC_#{n})")
201
- makefile.puts ""
232
+ def make_tests_rules(makefile, deps)
233
+ cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
234
+ @all_names.each do |n|
235
+ next unless n.start_with? 'TEST_'
236
+ filename = "#{@workspace.tests_short}/#{n.downcase}.#{@workspace.source_suffix}"
237
+ objs = ["$(OBJ_#{n})"] + extract_one_file_obj(filename, deps).map do |o|
238
+ "$(OBJ_#{File.basename(o, '.*').upcase})"
239
+ end
240
+
241
+ makefile.puts("$(#{n}): #{objs.join ' '}\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $@ $^ $(LDFLAGS) $(LDLIBS)")
242
+ makefile.puts ''
243
+ end
202
244
  end
203
245
 
204
- if @workspace.mode == :bin
205
- makefile.puts("BIN: $(OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(wildcard ./obj/*.o) $(LDFLAGS) $(LDLIBS)")
206
- else
207
- makefile.puts("LIB: $(OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -shared -o $(TARGET) $(wildcard ./obj/*.o) -fPIC $(LDFLAGS) $(LDLIBS)")
246
+ def make_clean(makefile)
247
+ clean = <<~DOC
248
+ .PHONY: clean
249
+ clean:
250
+ \trm ./target/*
251
+ \trm ./obj/*.o
252
+ DOC
253
+ makefile.puts(clean)
208
254
  end
209
- makefile.puts ""
210
255
 
211
- clean = <<~DOC
212
- .PHONY: clean
213
- clean:
214
- \trm $(TARGET)
215
- \trm ./obj/*.o
216
- DOC
217
- makefile.puts(clean)
256
+ def make_rules(makefile, deps)
257
+ make_dependencies makefile, deps
258
+ makefile.puts ''
259
+ make_obj_rules makefile, deps
260
+ makefile.puts ''
261
+ make_out_rules makefile, deps
262
+ makefile.puts ''
263
+ make_tests_rules makefile, deps
264
+ makefile.puts ''
265
+ make_clean makefile
266
+ end
218
267
  end
219
- end
220
268
 
221
- class WorkSpace
222
- def make
223
- config = ConfigReader.extract_flags "config.json"
269
+ class WorkSpace
270
+ def make
271
+ config = ConfigReader.extract_flags "config.json"
224
272
 
225
- deps = File.exist?(@deps) ?
226
- DepAnalyzer.read_from(@deps) :
227
- DepAnalyzer.new("./src").build_to_file(["./src", "./src/components"], @deps)
273
+ deps = target_deps.merge tests_deps
228
274
 
229
- makefile = Makefile.new(self)
230
- makefile.configure(config)
231
- makefile.make!(deps)
275
+ makefile = Makefile.new self
276
+ makefile.configure config
277
+ makefile.make! deps
278
+ end
232
279
  end
233
280
  end