canoe 0.3.1 → 0.3.2.3

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,28 @@
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(arg = 'all')
5
+ send "clean_#{arg}"
6
+ end
5
7
 
6
- private
8
+ private
7
9
 
8
- def clean_obj
9
- puts "rm -f ./obj/*.o"
10
- system "rm -f ./obj/*.o"
11
- end
10
+ def clean_all
11
+ clean_target
12
+ clean_obj
13
+ end
12
14
 
13
- def clean_target
14
- puts "rm -f ./target/*"
15
- system "rm -f ./target/*"
16
- end
15
+ def clean_target
16
+ issue_command 'rm ./target/* -rf'
17
+ end
17
18
 
18
- def clean_bin
19
- clean_obj
20
- clean_target
21
- end
19
+ def clean_obj
20
+ issue_command 'rm ./obj/* -rf'
21
+ end
22
22
 
23
- def clean_lib
24
- clean_obj
25
- clean_target
23
+ def clean_tests
24
+ issue_command 'rm ./obj/test_* -rf'
25
+ issue_command 'rm ./target/test_* -rf'
26
+ end
26
27
  end
27
28
  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,232 +1,279 @@
1
- class Makefile
2
- def initialize(workspace)
3
- @workspace = workspace
4
- @all_names = []
5
- @common_variables = {}
6
- @src_variables = {}
7
- @hdr_variables = {}
8
- @obj_variables = {}
9
- @config = {}
10
- end
1
+ # If the project has circular dependency, this command would fail
2
+ module Canoe
3
+ ##
4
+ # CanoeMakefile is used to offer makefile generation utilities
5
+ class CanoeMakefile
6
+ include WorkSpaceUtil
7
+ def initialize(workspace)
8
+ @workspace = workspace
9
+ @all_names = []
10
+ @common_variables = {}
11
+ @src_variables = {}
12
+ @hdr_variables = {}
13
+ @obj_variables = {}
14
+ @config = {}
15
+ end
11
16
 
12
- def configure(config)
13
- @config = config
14
- end
17
+ def configure(config)
18
+ @config = config
19
+ end
15
20
 
16
- def make!(deps)
17
- File.open("Makefile", "w") do |f|
18
- if cxx?(get_compiler)
19
- make_cxx(f, deps)
20
- else
21
- make_c(f, deps)
21
+ def make!(deps)
22
+ File.open('Makefile', 'w') do |f|
23
+ if cxx?(get_compiler)
24
+ make_cxx(f, deps)
25
+ else
26
+ make_c(f, deps)
27
+ end
22
28
  end
23
29
  end
24
- end
25
30
 
26
- private
31
+ private
27
32
 
28
- def get_compiler
29
- @config["compiler"]
30
- end
33
+ def get_compiler
34
+ @config['compiler']
35
+ end
31
36
 
32
- def get_header_suffix
33
- @workspace.header_suffix
34
- end
37
+ def get_header_suffix
38
+ @workspace.header_suffix
39
+ end
35
40
 
36
- def get_source_suffix
37
- @workspace.source_suffix
38
- end
41
+ def get_source_suffix
42
+ @workspace.source_suffix
43
+ end
39
44
 
40
- def get_compiling_flags
41
- flags = @config["flags"]["compile"].values.join " "
42
- flags + " -I./src/components"
43
- end
45
+ def get_compiling_flags
46
+ flags = @config['flags']['compile'].values.join ' '
47
+ flags + ' -I./src/components'
48
+ end
44
49
 
45
- def get_ldflags
46
- @config["flags"]["link"].values.select { |v| v.start_with?("-L") }.join " "
47
- end
50
+ def get_ldflags
51
+ @config['flags']['link'].values.select { |v| v.start_with?('-L') }.join ' '
52
+ end
48
53
 
49
- def get_ldlibs
50
- (@config["flags"]["link"].values - (get_ldflags.split)).join " "
51
- end
54
+ def get_ldlibs
55
+ (@config['flags']['link'].values - (get_ldflags.split)).join ' '
56
+ end
52
57
 
53
- def cxx?(name)
54
- return get_compiler.end_with? "++"
55
- end
58
+ def cxx?(name)
59
+ return get_compiler.end_with? '++'
60
+ end
56
61
 
57
- def make_cxx(makefile, deps)
58
- make_common(makefile, "CXX", deps)
59
- end
62
+ def make_cxx(makefile, deps)
63
+ make_common(makefile, 'CXX', deps)
64
+ end
60
65
 
61
- def make_c(makefile, deps)
62
- make_common(makefile, "CC", deps)
63
- end
66
+ def make_c(makefile, deps)
67
+ make_common(makefile, 'CC', deps)
68
+ end
64
69
 
65
- def make_common(makefile, compiler_prefix, deps)
66
- make_compiling_info(makefile, compiler_prefix)
67
- define_variables(makefile, deps)
68
- make_rules(makefile, deps)
69
- end
70
+ def make_common(makefile, compiler_prefix, deps)
71
+ make_compiling_info(makefile, compiler_prefix)
72
+ define_variables(makefile, deps)
73
+ make_rules(makefile, deps)
74
+ end
70
75
 
71
- def make_compiling_info(makefile, compiler_prefix)
72
- makefile.puts("#{compiler_prefix}=#{get_compiler}")
73
- makefile.puts("#{compiler_prefix}FLAGS=#{get_compiling_flags}")
74
- makefile.puts("LDFLAGS=#{get_ldflags}")
75
- makefile.puts("LDLIBS=#{get_ldlibs}")
76
- makefile.puts ""
77
- end
76
+ def make_compiling_info(makefile, compiler_prefix)
77
+ makefile.puts("#{compiler_prefix}=#{get_compiler}")
78
+ makefile.puts("#{compiler_prefix}FLAGS=#{get_compiling_flags}")
79
+ makefile.puts("LDFLAGS=#{get_ldflags}")
80
+ makefile.puts("LDLIBS=#{get_ldlibs}")
81
+ makefile.puts ''
82
+ end
78
83
 
79
- def define_variables(makefile, deps)
80
- define_dirs(makefile)
81
-
82
- src_files = deps.keys.select { |f| f.end_with? get_source_suffix }
83
- generate_all_names(src_files)
84
- define_srcs(makefile, src_files)
85
- makefile.puts ""
86
- define_hdrs(makefile, src_files)
87
- makefile.puts ""
88
- define_objs(makefile, src_files)
89
- makefile.puts ""
90
- end
84
+ def define_variables(makefile, deps)
85
+ define_dirs(makefile)
86
+ src_files = deps.keys.select { |f| f.end_with? get_source_suffix }
87
+
88
+ generate_all_names(src_files)
89
+ define_srcs(makefile, src_files)
90
+ makefile.puts ''
91
+ define_hdrs(makefile, src_files)
92
+ makefile.puts ''
93
+ define_objs(makefile, src_files)
94
+ makefile.puts ''
95
+ define_tests(makefile, src_files)
96
+ makefile.puts ''
97
+ end
91
98
 
92
- def extract_name(name, prefix)
93
- if name.start_with?(prefix)
94
- name.delete_suffix(File.extname(name))[prefix.length..].gsub("/", "_")
95
- else
96
- File.basename(name.split("/")[-1], ".*")
99
+ def extract_name(name, _)
100
+ File.basename(file_to_obj(name), '.*')
97
101
  end
98
- end
99
102
 
100
- def generate_all_names(files)
101
- files.each do |f|
102
- name = extract_name(f, @workspace.components_prefix).upcase
103
- @all_names << name
104
- @src_variables[name] = f
105
- @hdr_variables[name] = f.gsub(@workspace.source_suffix, @workspace.header_suffix)
106
- @obj_variables[name] = @workspace.obj_prefix + extract_name(f, @workspace.components_prefix) + ".o"
103
+ def generate_all_names(files)
104
+ files.each do |f|
105
+ name = extract_name(f, @workspace.components_prefix).upcase
106
+ @all_names << name
107
+ @src_variables[name] = f
108
+ @hdr_variables[name] = f.gsub @workspace.source_suffix, @workspace.header_suffix
109
+ @obj_variables[name] = file_to_obj(f)
110
+ end
107
111
  end
108
- end
109
112
 
110
- def define_dirs(makefile)
111
- makefile.puts("TARGET_DIR=./target")
112
- if @workspace.mode == :bin
113
- makefile.puts("TARGET=$(TARGET_DIR)/#{@workspace.name}")
114
- else
115
- makefile.puts("TARGET=$(TARGET_DIR)/lib#{@workspace.name.downcase}.so")
116
- end
117
- # note the ending slash
118
- makefile.puts("OBJ_DIR=#{@workspace.obj_prefix[..-2]}")
119
- makefile.puts("SRC_DIR=#{@workspace.src_prefix[..-2]}")
120
- makefile.puts("COMPONENTS_DIR=#{@workspace.components_prefix[..-2]}")
121
- makefile.puts ""
122
- end
113
+ def define_dirs(makefile)
114
+ makefile.puts("TARGET_DIR=./target")
115
+ if @workspace.mode == :bin
116
+ makefile.puts("TARGET=$(TARGET_DIR)/#{@workspace.name}")
117
+ else
118
+ makefile.puts("TARGET=$(TARGET_DIR)/lib#{@workspace.name.downcase}.so")
119
+ end
120
+ # note the ending slash
121
+ makefile.puts("OBJ_DIR=#{@workspace.obj_prefix[..-2]}")
122
+ makefile.puts("SRC_DIR=#{@workspace.src_prefix[..-2]}")
123
+ makefile.puts("COMPONENTS_DIR=#{@workspace.components_prefix[..-2]}")
124
+ makefile.puts ""
125
+ end
123
126
 
124
- def define_srcs(makefile, files)
125
- @src_variables.each do |k, v|
126
- makefile.puts("SRC_#{k}=#{v}")
127
+ def define_srcs(makefile, files)
128
+ @src_variables.each do |k, v|
129
+ makefile.puts("SRC_#{k}=#{v}")
130
+ end
127
131
  end
128
- end
129
132
 
130
- def define_hdrs(makefile, files)
131
- @hdr_variables.each do |k, v|
132
- next if k == "MAIN"
133
- makefile.puts("HDR_#{k}=#{v}")
133
+ def define_hdrs(makefile, files)
134
+ @hdr_variables.each do |k, v|
135
+ next if k == "MAIN"
136
+ makefile.puts("HDR_#{k}=#{v}") if File.exist? v
137
+ end
134
138
  end
135
- end
136
139
 
137
- def define_objs(makefile, files)
138
- @obj_variables.each do |k, v|
139
- makefile.puts("OBJ_#{k}=#{v}")
140
+ def define_objs(makefile, files)
141
+ @obj_variables.each do |k, v|
142
+ makefile.puts("OBJ_#{k}=#{v}")
143
+ end
144
+ objs = @obj_variables.keys.map { |k| "$(OBJ_#{k})" }
145
+ bin_objs = objs.reject { |o| o.start_with? '$(OBJ_TEST'}
146
+ test_objs = objs - bin_objs
147
+ makefile.puts ''
148
+ makefile.puts("OUT_OBJS=#{bin_objs.join ' '}")
149
+ makefile.puts("TEST_OBJS=#{test_objs.join ' '}")
140
150
  end
141
- objs = @obj_variables.keys.map { |k| "$(OBJ_#{k})" }.join " "
142
- makefile.puts("OBJS=#{objs}")
143
- makefile.puts ""
144
- end
145
151
 
146
- def get_all_dep_name(file_name, deps)
147
- dep = deps[file_name]
148
- if dep.empty?
149
- []
150
- else
151
- tmp = dep.map { |n| extract_name(n, @workspace.components_prefix).upcase }
152
- dep.each do |d|
153
- tmp += get_all_dep_name(d, deps)
152
+ def define_tests(makefile, files)
153
+ test_files = files.select { |f| File.basename(f, '.*').start_with? 'test_'}
154
+ test_files.each do |f|
155
+ basename = File.basename(f, '.*')
156
+ test = "#{@workspace.target_short}/#{basename}"
157
+ makefile.puts("#{basename.upcase}=#{test}")
154
158
  end
155
- tmp
159
+ tests = test_files.map do |f|
160
+ "$(#{File.basename(f, '.*').upcase})"
161
+ end
162
+ makefile.puts("TESTS=#{tests.join ' '}")
156
163
  end
157
- end
158
164
 
159
- def emit_dependencies(makefile, name, deps)
160
- as_str = deps.map do |n|
161
- if n == name
162
- ["$(SRC_#{n})"] + ["$(HDR_#{n})"] * (name == "MAIN" ? 0 : 1)
165
+ def get_all_dep_name(file_name, deps)
166
+ dep = deps[file_name]
167
+ if dep.empty?
168
+ []
163
169
  else
164
- "$(#{n}_DEP)"
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)
173
+ end
174
+ tmp
165
175
  end
166
- end.flatten.join " "
167
- makefile.puts("#{name}_DEP=#{as_str}")
168
- end
176
+ end
169
177
 
170
- def make_dependencies(makefile, deps)
171
- dep_variables = Hash[@all_names.map { |n| [n, []] }]
172
- reference = Hash[@all_names.map { |n| [n, []] }]
173
- @all_names.each do |n|
174
- dep_variables[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
175
- reference[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
178
+ def emit_dependencies(makefile, name, deps)
179
+ as_str = deps.map do |n|
180
+ if n == name
181
+ ["$(SRC_#{n})"] + ["$(HDR_#{n})"] * (name == "MAIN" ? 0 : 1)
182
+ else
183
+ "$(#{n}_DEP)"
184
+ end
185
+ end.flatten.join " "
186
+ makefile.puts("#{name}_DEP=#{as_str}")
176
187
  end
177
188
 
178
- # deduplication
179
- dep_variables.each do |k, v|
180
- v.each do |n|
181
- next if n == k
182
- v = v - reference[n] + [n] if v.include? n
189
+ def make_dependencies(makefile, deps)
190
+ dep_variables = Hash[@all_names.map { |n| [n, []] }]
191
+ reference = Hash[@all_names.map { |n| [n, []] }]
192
+ @all_names.each do |n|
193
+ dep_variables[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
194
+ reference[n] = ([n] + get_all_dep_name(@src_variables[n], deps)).uniq
195
+ end
196
+
197
+ # deduplication
198
+ dep_variables.each do |k, v|
199
+ v.each do |n|
200
+ next if n == k
201
+ v = v - reference[n] + [n] if v.include? n
202
+ end
203
+ dep_variables[k] = v
204
+ end
205
+
206
+ dep_variables.each do |k, v|
207
+ emit_dependencies(makefile, k, v)
183
208
  end
184
- dep_variables[k] = v
185
209
  end
186
210
 
187
- dep_variables.each do |k, v|
188
- emit_dependencies(makefile, k, v)
211
+ def make_obj_rules(makefile, deps)
212
+ cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
213
+
214
+ @all_names.each do |n|
215
+ makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $@ -c $(SRC_#{n})\n\n")
216
+ end
189
217
  end
190
- end
191
218
 
192
- def make_rules(makefile, deps)
193
- make_dependencies(makefile, deps)
194
- makefile.puts ""
195
- makefile.puts("all: BIN\n")
196
- makefile.puts ""
197
- cmplr = cxx?(get_compiler) ? "CXX" : "CC"
198
- @all_names.each do |n|
199
- makefile.puts("$(OBJ_#{n}): $(#{n}_DEP)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(OBJ_#{n}) -c $(SRC_#{n})")
200
- makefile.puts ""
219
+ def make_out_rules(makefile, deps)
220
+ cmplr = cxx?(get_compiler) ? 'CXX' : 'CC'
221
+ if @workspace.mode == :bin
222
+ makefile.puts("out: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(OUT_OBJS) $(LDFLAGS) $(LDLIBS)")
223
+ else
224
+ makefile.puts("out: $(OUT_OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -shared -o $(TARGET) $(OUT_OBJS) -fPIC $(LDFLAGS) $(LDLIBS)")
225
+ end
226
+ makefile.puts ''
227
+ makefile.puts("test: $(TESTS)")
228
+ makefile.puts ''
229
+ makefile.puts("all: out test")
230
+ end
231
+
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
201
244
  end
202
245
 
203
- if @workspace.mode == :bin
204
- makefile.puts("BIN: $(OBJS)\n\t$(#{cmplr}) $(#{cmplr}FLAGS) -o $(TARGET) $(wildcard ./obj/*.o) $(LDFLAGS) $(LDLIBS)")
205
- else
206
- 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)
207
254
  end
208
- makefile.puts ""
209
255
 
210
- clean = <<~DOC
211
- .PHONY: clean
212
- clean:
213
- \trm $(TARGET)
214
- \trm ./obj/*.o
215
- DOC
216
- makefile.puts(clean)
256
+ def make_rules(makefile, deps)
257
+ make_dependencies makefile, deps
258
+ makefile.puts ''
259
+ make_out_rules makefile, deps
260
+ makefile.puts ''
261
+ make_obj_rules makefile, deps
262
+ make_tests_rules makefile, deps
263
+ makefile.puts ''
264
+ make_clean makefile
265
+ end
217
266
  end
218
- end
219
267
 
220
- class WorkSpace
221
- def make
222
- config = ConfigReader.extract_flags "config.json"
268
+ class WorkSpace
269
+ def make
270
+ config = ConfigReader.extract_flags "config.json"
223
271
 
224
- deps = File.exist?(@deps) ?
225
- DepAnalyzer.read_from(@deps) :
226
- DepAnalyzer.new("./src").build_to_fil
272
+ deps = target_deps.merge tests_deps
227
273
 
228
- makefile = Makefile.new(self)
229
- makefile.configure(config)
230
- makefile.make!(deps)
274
+ makefile = CanoeMakefile.new self
275
+ makefile.configure config
276
+ makefile.make! deps
277
+ end
231
278
  end
232
279
  end