canoe 0.3.0.2 → 0.3.1

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: acf64e52f86562fbb4103263adf6ac25d3583fdd8cc935df460d6df89ffa4367
4
- data.tar.gz: 8f3e6ba476da88e1cd34abffb4bfa70e0ac910fb5bc93977601df49e44a75735
3
+ metadata.gz: af31768c0b36d635c13ff31e41dc772dd9834ccd2d52e791f399053ebb3b9782
4
+ data.tar.gz: 135f95f9631bcc43c4817833ee9a6075b1d336239b9131c8f5f26d3f0006cd3b
5
5
  SHA512:
6
- metadata.gz: e39ce423d813c64ef43c4440990439463a99dcb724771adc2d4d5db130c8206d7a3801c9fd036ee1477cd5c162f19b3da3dbc123e6114cba5bc7d8c0bf7d03a0
7
- data.tar.gz: fe49d0b455bb21deb30b149f08736e2cff7091d8a3d38f87ac395fa1800c8b9abdb7c17594007412f5aacce448da5ebb60fd9a986fbf2ab645737aa59cd9100f
6
+ metadata.gz: 9c82734822d59c1cd1a119dcc55f954f3d6b971457f44df22c8e9f6eceaa638c503816a1f05dc54019ea8ded2c70f1431e26cab0c057db3cd4ee2775dc12583c
7
+ data.tar.gz: 9b23406264a260e2b715018f5ad275c6a8b9293d712fd4d7623b03709fa5d93ee03cbc916472d9b24e9e6e1d4e2dd83e6781903ca7987febc4ec28a3e92e0ce5
data/lib/canoe.rb CHANGED
@@ -4,21 +4,22 @@ require_relative "source_files"
4
4
 
5
5
  class Canoe
6
6
  def initialize
7
- options = ['new',
8
- 'add',
9
- 'build',
10
- 'generate',
11
- 'run',
12
- 'dep',
13
- 'clean',
14
- 'version',
15
- 'help',
16
- 'update',
17
- 'test']
7
+ options = ["new",
8
+ "add",
9
+ "build",
10
+ "generate",
11
+ "make",
12
+ "run",
13
+ "dep",
14
+ "clean",
15
+ "version",
16
+ "help",
17
+ "update",
18
+ "test"]
18
19
  @cmd = CmdParser.new options
19
20
  end
20
21
 
21
22
  def parse(args)
22
- @cmd.parse args
23
+ @cmd.parse args
23
24
  end
24
25
  end
data/lib/cmd.rb CHANGED
@@ -7,13 +7,14 @@ require_relative "config_reader"
7
7
  # Parsing command arguments passed to canoe
8
8
  class CmdParser
9
9
  include Err
10
+
10
11
  def initialize(options)
11
- @options = options
12
+ @options = options
12
13
  end
13
14
 
14
15
  def parse(args)
15
- if args.size < 1
16
- abort_on_err "please give one command among #{@options.join(', ')}"
16
+ if args.size < 1
17
+ abort_on_err "please give one command among #{@options.join(", ")}"
17
18
  end
18
19
 
19
20
  unless @options.include?(args[0])
@@ -24,6 +25,7 @@ class CmdParser
24
25
  end
25
26
 
26
27
  private
28
+
27
29
  def get_current_workspace
28
30
  abort_on_err "not in a canoe workspace" unless File.exists? ".canoe"
29
31
  config = ConfigReader.extract_flags("config.json")
@@ -34,7 +36,7 @@ class CmdParser
34
36
  name = Dir.pwd.split("/")[-1]
35
37
  mode = File.exists?("src/main.#{src_sfx}") ? :bin : :lib
36
38
 
37
- Dir.chdir('..') do
39
+ Dir.chdir("..") do
38
40
  return WorkSpace.new(name, mode, src_sfx, hdr_sfx)
39
41
  end
40
42
  end
@@ -44,10 +46,10 @@ class CmdParser
44
46
 
45
47
  name, mode = nil, "bin"
46
48
  suffixes = ["cpp", "hpp"]
47
-
49
+
48
50
  args.each do |arg|
49
51
  case arg
50
- when '--bin', '--lib'
52
+ when "--bin", "--lib"
51
53
  mode = arg[2..]
52
54
  when /--suffix=(\w+)\:(\w+)/
53
55
  suffixes[0], suffixes[1] = $1, $2
@@ -55,7 +57,7 @@ class CmdParser
55
57
  name = arg unless name
56
58
  end
57
59
  end
58
-
60
+
59
61
  abort_on_err("please give a name to this project") unless name
60
62
  WorkSpace.new(name, mode.to_sym, suffixes[0], suffixes[1]).new
61
63
  end
@@ -67,7 +69,7 @@ class CmdParser
67
69
 
68
70
  get_current_workspace.add args
69
71
  end
70
-
72
+
71
73
  def parse_build(args)
72
74
  get_current_workspace.build args
73
75
  end
@@ -75,15 +77,15 @@ class CmdParser
75
77
  def parse_generate(args)
76
78
  get_current_workspace.generate
77
79
  end
78
-
80
+
79
81
  def parse_run(args)
80
82
  get_current_workspace.run args
81
83
  end
82
84
 
83
85
  def parse_dep(args)
84
- get_current_workspace.dep
86
+ get_current_workspace.dep
85
87
  end
86
-
88
+
87
89
  def parse_clean(args)
88
90
  get_current_workspace.clean
89
91
  end
@@ -94,16 +96,16 @@ class CmdParser
94
96
 
95
97
  def parse_version(args)
96
98
  puts <<~VER
97
- canoe v0.3.0.2
98
- For features in this version, please visit https://github.com/Dicridon/canoe
99
- Currently, canoe can do below:
100
- - project creation
101
- - project auto build and run (works like Cargo for Rust)
102
- - project structure management
103
- by XIONG Ziwei
104
- VER
99
+ canoe v0.3.1
100
+ For features in this version, please visit https://github.com/Dicridon/canoe
101
+ Currently, canoe can do below:
102
+ - project creation
103
+ - project auto build and run (works like Cargo for Rust)
104
+ - project structure management
105
+ by XIONG Ziwei
106
+ VER
105
107
  end
106
-
108
+
107
109
  def parse_help(args)
108
110
  WorkSpace.help
109
111
  end
@@ -111,4 +113,8 @@ class CmdParser
111
113
  def parse_update(args)
112
114
  get_current_workspace.update
113
115
  end
116
+
117
+ def parse_make(args)
118
+ get_current_workspace.make
119
+ end
114
120
  end
data/lib/coloring.rb CHANGED
@@ -3,14 +3,14 @@
3
3
  class String
4
4
  def self.define_coloring_methods
5
5
  colors = {
6
- 30 => :black,
7
- 31 => :red,
8
- 32 => :green,
9
- 33 => :yellow,
10
- 34 => :blue,
11
- 35 => :magenta,
12
- 36 => :cyan,
13
- 37 => :white
6
+ 30 => :black,
7
+ 31 => :red,
8
+ 32 => :green,
9
+ 33 => :yellow,
10
+ 34 => :blue,
11
+ 35 => :magenta,
12
+ 36 => :cyan,
13
+ 37 => :white,
14
14
  }
15
15
  colors.each do |k, v|
16
16
  define_method v do
@@ -20,4 +20,4 @@ class String
20
20
  end
21
21
 
22
22
  define_coloring_methods
23
- end
23
+ end
data/lib/compiler.rb CHANGED
@@ -20,7 +20,6 @@ class Compiler
20
20
  @linking_flags.join " "
21
21
  end
22
22
 
23
-
24
23
  def append_compiling_flag(flag)
25
24
  @compiling_flags << flag
26
25
  end
@@ -43,7 +42,7 @@ class Compiler
43
42
  puts "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
44
43
  system "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
45
44
  end
46
-
45
+
47
46
  def inspect
48
47
  puts "compiler name: #{name.inspect}"
49
48
  puts "compiler flags: #{flags.inspect}"
data/lib/config_reader.rb CHANGED
@@ -1,4 +1,4 @@
1
- require 'json'
1
+ require "json"
2
2
 
3
3
  ##
4
4
  # class ConfigReader
data/lib/default_files.rb CHANGED
@@ -10,9 +10,9 @@ class DefaultFiles
10
10
  end
11
11
  end
12
12
 
13
- def create_config(path, src_sfx='cpp', hdr_sfx='hpp')
13
+ def create_config(path, src_sfx = "cpp", hdr_sfx = "hpp")
14
14
  open_file_and_write(
15
- "#{path}/config.json",
15
+ "#{path}/config.json",
16
16
  <<~CONFIG
17
17
  {
18
18
  "compiler": "clang++",
@@ -30,10 +30,11 @@ class DefaultFiles
30
30
  }
31
31
  }
32
32
  CONFIG
33
- )
33
+
34
+ )
34
35
  end
35
36
 
36
- def create_main(path, suffix='cpp')
37
+ def create_main(path, suffix = "cpp")
37
38
  open_file_and_write(
38
39
  "#{path}/main.#{suffix}",
39
40
  <<~DOC
@@ -42,10 +43,11 @@ class DefaultFiles
42
43
  std::cout << "hello world!" << std::endl;
43
44
  }
44
45
  DOC
45
- )
46
+
47
+ )
46
48
  end
47
49
 
48
- def create_lib_header(path, lib_name, suffix='hpp')
50
+ def create_lib_header(path, lib_name, suffix = "hpp")
49
51
  open_file_and_write(
50
52
  "#{path}/#{lib_name}.#{suffix}",
51
53
  <<~DOC
@@ -54,7 +56,8 @@ class DefaultFiles
54
56
 
55
57
  #endif
56
58
  DOC
57
- )
59
+
60
+ )
58
61
  end
59
62
 
60
63
  # def create_emacs_dir_local(path)
@@ -69,16 +72,17 @@ class DefaultFiles
69
72
  # )
70
73
  # end
71
74
 
72
- def create_cpp(filename, src_sfx='cpp', hdr_sfx='hpp')
75
+ def create_cpp(filename, src_sfx = "cpp", hdr_sfx = "hpp")
73
76
  open_file_and_write(
74
- "#{filename}.#{src_sfx}",
77
+ "#{filename}.#{src_sfx}",
75
78
  <<~DOC
76
79
  #include "#{filename}.#{hdr_sfx}"
77
80
  DOC
78
- )
81
+
82
+ )
79
83
  end
80
84
 
81
- def create_hpp(workspace, prefix, filename, hdr_sfx='hpp')
85
+ def create_hpp(workspace, prefix, filename, hdr_sfx = "hpp")
82
86
  open_file_and_write(
83
87
  "#{filename}.#{hdr_sfx}",
84
88
  <<~DOC
@@ -87,7 +91,8 @@ class DefaultFiles
87
91
 
88
92
  #endif
89
93
  DOC
90
- )
94
+
95
+ )
91
96
  end
92
97
  end
93
98
  end
data/lib/dependence.rb CHANGED
@@ -1,11 +1,11 @@
1
- require_relative 'source_files'
2
- require_relative 'err'
1
+ require_relative "source_files"
2
+ require_relative "err"
3
3
 
4
4
  ##
5
5
  # class DepAnalyzer
6
- # This class is the key component of canoe, which offers file dependency analysis functionality.
6
+ # This class is the key component of canoe, which offers file dependency analysis functionality.
7
7
  # A DepAnalyzer takes a directory as input, sources files and corresponding header files in this
8
- # directory should have same name, i.e. test.cpp and test.hpp.
8
+ # directory should have same name, e.g. test.cpp and test.hpp.
9
9
  # DepAnalyzer would read every source file and recursively process user header files included in this source file to
10
10
  # find out all user header files this source file depends on.
11
11
  # Based on dependencies built in previous stage, DepAnalyzer determines which files should be recompiled and return
@@ -20,15 +20,15 @@ class DepAnalyzer
20
20
  File.open(filename, "r") do |f|
21
21
  ret = Hash.new []
22
22
  f.each_with_index do |line, i|
23
- entry = line.split(': ')
24
- Err.abort_on_err("Bad .canoe.deps format, line #{i+1}") unless entry.length == 2
23
+ entry = line.split(": ")
24
+ Err.abort_on_err("Bad .canoe.deps format, line #{i + 1}") unless entry.length == 2
25
25
  ret[entry[0]] = entry[1].split
26
- end
26
+ end
27
27
  ret
28
28
  end
29
29
  end
30
30
 
31
- def self.compiling_filter(deps, build_time, src_sfx='cpp', hdr_sfx='hpp')
31
+ def self.compiling_filter(deps, build_time, src_sfx = "cpp", hdr_sfx = "hpp")
32
32
  files = []
33
33
  @processed = {}
34
34
  @recompiles = {}
@@ -57,6 +57,7 @@ class DepAnalyzer
57
57
  end
58
58
 
59
59
  private
60
+
60
61
  def self.mark(file, build_time, deps)
61
62
  ret = false
62
63
  return false unless File.exists? file
@@ -71,21 +72,21 @@ class DepAnalyzer
71
72
  @processed[f] = true
72
73
  if mark(f, build_time, deps)
73
74
  @recompiles[f] = true
74
- return true
75
+ return true
75
76
  end
76
77
  end
77
78
  end
78
79
  ret
79
80
  end
80
81
 
81
- def self.should_recompile?(file, build_time)
82
+ def self.should_recompile?(file, build_time)
82
83
  judge = build_time
83
84
  if build_time == Time.new(0)
84
85
  objfile = if file.start_with?("./src/components")
85
- './obj/' + file.delete_suffix(File.extname(file))['./src/components/'.length..].gsub('/', '_') + '.o'
86
- else
87
- "./obj/#{File.basename(file, ".*")}.o"
88
- end
86
+ "./obj/" + file.delete_suffix(File.extname(file))["./src/components/".length..].gsub("/", "_") + ".o"
87
+ else
88
+ "./obj/#{File.basename(file, ".*")}.o"
89
+ end
89
90
  return true unless File.exists? objfile
90
91
  judge = File.mtime(objfile)
91
92
  end
@@ -93,7 +94,8 @@ class DepAnalyzer
93
94
  end
94
95
 
95
96
  public
96
- def initialize(dir, src_sfx='cpp', hdr_sfx='hpp')
97
+
98
+ def initialize(dir, src_sfx = "cpp", hdr_sfx = "hpp")
97
99
  @dir = dir
98
100
  @deps = Hash.new []
99
101
  @source_suffix = src_sfx
@@ -115,25 +117,26 @@ class DepAnalyzer
115
117
 
116
118
  def build_to_file(include_path, filename)
117
119
  build_dependence include_path
118
-
120
+
119
121
  File.open(filename, "w") do |f|
120
122
  @deps.each do |k, v|
121
123
  f.write "#{k}: #{v.join(" ")}\n"
122
124
  end
123
125
  end
124
-
126
+
125
127
  @deps
126
128
  end
127
129
 
128
130
  private
129
- def get_all_headers(include_path, file, suffix='hpp')
131
+
132
+ def get_all_headers(include_path, file, suffix = "hpp")
130
133
  File.open(file, "r") do |f|
131
134
  ret = []
132
135
  if file.end_with?(".#{@source_suffix}")
133
136
  header = file.sub(".#{@source_suffix}", ".#{@header_suffix}")
134
137
  ret += [header] if File.exists?(header)
135
138
  end
136
-
139
+
137
140
  f.each_line do |line|
138
141
  if mat = line.match(/include "(.+\.#{suffix})"/)
139
142
  include_path.each do |path|
@@ -142,7 +145,7 @@ class DepAnalyzer
142
145
  end
143
146
  end
144
147
  end
145
-
148
+
146
149
  ret.uniq
147
150
  end
148
151
  end
data/lib/err.rb CHANGED
@@ -1,4 +1,5 @@
1
- require_relative 'coloring'
1
+ require_relative "coloring"
2
+
2
3
  module Err
3
4
  def warn_on_err(err)
4
5
  puts <<~ERR
@@ -13,8 +14,8 @@ module Err
13
14
  #{"Fatal: ".red}
14
15
  #{err}
15
16
  try 'canoe help' for more information
16
- ERR
17
+ ERR
17
18
  end
18
19
 
19
20
  module_function :warn_on_err, :abort_on_err
20
- end
21
+ end
data/lib/source_files.rb CHANGED
@@ -5,7 +5,7 @@ class SourceFiles
5
5
  class << self
6
6
  def get_all(dir, &block)
7
7
  @files = []
8
- get_all_helper(dir, &block)
8
+ get_all_helper(dir, &block)
9
9
  @files
10
10
  end
11
11
 
@@ -19,13 +19,14 @@ class SourceFiles
19
19
  else
20
20
  @files << "#{file}"
21
21
  end
22
- end
22
+ end
23
23
  end
24
-
24
+
25
25
  @files
26
26
  end
27
27
 
28
28
  private
29
+
29
30
  def get_all_helper(dir, &block)
30
31
  Dir.each_child(dir) do |f|
31
32
  file = "#{dir}/#{f}"
@@ -42,4 +43,3 @@ class SourceFiles
42
43
  end
43
44
  end
44
45
  end
45
-
data/lib/workspace/add.rb CHANGED
@@ -8,19 +8,20 @@ class WorkSpace
8
8
  dir += "/#{filename}"
9
9
  prefix << filename
10
10
  unless Dir.exist? dir
11
- FileUtils.mkdir dir
11
+ FileUtils.mkdir dir
12
12
  Dir.chdir(dir) do
13
13
  puts "created " + Dir.pwd.blue
14
- create_working_files prefix.join('__'), filename
14
+ create_working_files prefix.join("__"), filename
15
15
  end
16
16
  end
17
17
  end
18
18
  end
19
19
  end
20
20
 
21
- private
21
+ private
22
+
22
23
  def create_working_files(prefix, filename)
23
24
  DefaultFiles.create_cpp filename, @source_suffix, @header_suffix
24
25
  DefaultFiles.create_hpp @name, prefix, filename, @header_suffix
25
26
  end
26
- end
27
+ end
@@ -1,5 +1,5 @@
1
1
  class WorkSpace
2
- # args are commandline parameters passed to `canoe build`,
2
+ # args are commandline parameters passed to `canoe build`,
3
3
  # could be 'all', 'test', 'target' or empty
4
4
  def build(args)
5
5
  case args[0]
@@ -12,8 +12,9 @@ class WorkSpace
12
12
  end
13
13
  end
14
14
 
15
- private
16
- def build_flags(flags, config)
15
+ private
16
+
17
+ def build_flags(flags, config)
17
18
  config.values.each do |v|
18
19
  case v
19
20
  when String
@@ -31,12 +32,12 @@ private
31
32
  def build_compiler_from_config
32
33
  Dir.chdir(@workspace) do
33
34
  flags = ConfigReader.extract_flags "config.json"
34
- compiler_name = flags['compiler'] ? flags['compiler'] : "clang++"
35
+ compiler_name = flags["compiler"] ? flags["compiler"] : "clang++"
35
36
  abort_on_err "compiler #{compiler_name} not found" unless File.exists?("/usr/bin/#{compiler_name}")
36
- compiler_flags = ['-Isrc/components']
37
+ compiler_flags = ["-Isrc/components"]
37
38
  linker_flags = []
38
39
 
39
- c_flags, l_flags = flags['flags']['compile'], flags['flags']['link']
40
+ c_flags, l_flags = flags["flags"]["compile"], flags["flags"]["link"]
40
41
  build_flags(compiler_flags, c_flags)
41
42
  build_flags(linker_flags, l_flags)
42
43
 
@@ -61,9 +62,9 @@ private
61
62
  def build_bin(files)
62
63
  # return if files.empty?
63
64
  build_compiler_from_config
64
- if build_common(files) && link_exectutable('./target', Dir.glob("obj/*.o"))
65
- puts "BUILDING SUCCEEDED".green
66
- else
65
+ if build_common(files) && link_exectutable("./target", Dir.glob("obj/*.o"))
66
+ puts "BUILDING SUCCEEDED".green
67
+ else
67
68
  puts "building FAILED".red
68
69
  end
69
70
  end
@@ -71,28 +72,28 @@ private
71
72
  def build_lib(files)
72
73
  # return if files.empty?
73
74
  build_compiler_from_config
74
- @compiler.append_compiling_flag '-fPIC'
75
- if build_common(files) && link_shared('./target', Dir.glob("obj/*.o"))
75
+ @compiler.append_compiling_flag "-fPIC"
76
+ if build_common(files) && link_shared("./target", Dir.glob("obj/*.o"))
76
77
  puts "BUILDING SUCCEEDED".green
77
- else
78
+ else
78
79
  puts "building FAILED".red
79
80
  end
80
81
  end
81
82
 
82
83
  def build_common(files)
83
- all = SourceFiles.get_all('./src') {|f| f.end_with? @source_suffix}
84
+ all = SourceFiles.get_all("./src") { |f| f.end_with? @source_suffix }
84
85
  total = all.size.to_f
85
86
  compiled = total - files.size
86
- comps = files.select {|f| f.start_with? @components_prefix}
87
+ comps = files.select { |f| f.start_with? @components_prefix }
87
88
  srcs = files - comps
88
- flag = true;
89
-
89
+ flag = true
90
+
90
91
  srcs.each do |f|
91
92
  progress = (compiled / total).round(2) * 100
92
93
  printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
93
94
  fname = f.split("/")[-1]
94
- o = @obj_prefix + File.basename(fname, ".*") + '.o'
95
- flag = false unless compile f, o
95
+ o = @obj_prefix + File.basename(fname, ".*") + ".o"
96
+ flag = false unless compile f, o
96
97
  compiled += 1
97
98
  end
98
99
 
@@ -100,7 +101,7 @@ private
100
101
  progress = (compiled / total).round(2) * 100
101
102
  printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
102
103
  o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
103
- .gsub('/', '_') + '.o'
104
+ .gsub("/", "_") + ".o"
104
105
  flag = false unless compile f, o
105
106
  compiled += 1
106
107
  end
@@ -113,9 +114,9 @@ private
113
114
  end
114
115
 
115
116
  def build_target
116
- deps = File.exist?(@deps) ?
117
- DepAnalyzer.read_from(@deps) :
118
- DepAnalyzer.new('./src').build_to_file(['./src', './src/components'], @deps)
117
+ deps = File.exist?(@deps) ?
118
+ DepAnalyzer.read_from(@deps) :
119
+ DepAnalyzer.new("./src").build_to_file(["./src", "./src/components"], @deps)
119
120
  target = "./target/#{@name}"
120
121
  build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
121
122
  files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
@@ -127,4 +128,4 @@ private
127
128
 
128
129
  self.send "build_#{@mode.to_s}", files
129
130
  end
130
- end
131
+ end
@@ -2,8 +2,9 @@ class WorkSpace
2
2
  def clean
3
3
  self.send "clean_#{@mode.to_s}"
4
4
  end
5
-
6
- private
5
+
6
+ private
7
+
7
8
  def clean_obj
8
9
  puts "rm -f ./obj/*.o"
9
10
  system "rm -f ./obj/*.o"
@@ -23,4 +24,4 @@ private
23
24
  clean_obj
24
25
  clean_target
25
26
  end
26
- end
27
+ end
data/lib/workspace/dep.rb CHANGED
@@ -4,9 +4,9 @@ class WorkSpace
4
4
  deps.each do |k, v|
5
5
  unless v.empty?
6
6
  puts "#{k.blue} depends on: "
7
- v.each {|f| puts " #{f.blue}"}
7
+ v.each { |f| puts " #{f.blue}" }
8
8
  puts ""
9
9
  end
10
10
  end
11
11
  end
12
- end
12
+ end
@@ -1,6 +1,5 @@
1
1
  class WorkSpace
2
2
  def generate
3
- DepAnalyzer.new('./src', @source_suffix, @header_suffix)
4
- .build_to_file ['./src', './src/components'], @deps
3
+ DepAnalyzer.new("./src", @source_suffix, @header_suffix).build_to_file ["./src", "./src/components"], @deps
5
4
  end
6
5
  end
@@ -1,71 +1,76 @@
1
1
  class WorkSpace
2
2
  def self.help
3
3
  info = <<~INFO
4
- canoe is a C/C++ project manager, inspired by Rust cargo.
5
- usage:
6
- canoe new tada: create a project named 'tada' in current directory
7
-
8
- canoe build: compile current project (execute this command in project directory)
9
-
10
- canoe generate: generate dependency relationships and store it in '.canoe.deps' file. Alias: update
4
+ canoe is a C/C++ project manager, inspired by Rust cargo.
5
+ usage:
6
+ canoe new tada: create a project named 'tada' in current directory
7
+
8
+ canoe build: compile current project (execute this command in project directory)
9
+
10
+ canoe generate: generate dependency relationships and store it in '.canoe.deps' file. Alias: update
11
11
 
12
- canoe update: udpate dependency relationships and store it in '.canoe.deps' file.
13
-
14
- canoe run: compile and execute current project (execute this command in project directory)
15
-
16
- canoe clean: remove all generated object files and binary files
17
-
18
- canoe help: show this help message
19
-
20
- canoe add tada: add a folder named tada under workspace/components,
21
-
22
- canoe dep: show current dependency relationships of current project
23
-
24
- canoe verion: version information
25
-
26
- new project_name [mode] [suffixes]:
27
- create a new project with project_name.
28
- In this project, four directories obj, src, target and third-party will be generated in project directory.
29
- in src, directory 'components' will be generated if [mode] is '--lib', an extra main.cpp will be generated if [mode] is '--bin'
30
-
31
- [mode]: --lib for a library and --bin for executable binaries
32
- [suffixes]: should be in 'source_suffix:header_suffix" format, notice the ':' between two suffixes
33
- add component_name:
34
- add a folder named tada under workspace/components.
35
- two files tada.hpp and tada.cpp would be craeted and intialized. File suffix may differ according users' specifications.
36
- if component_name is a path separated by '/', then canoe would create folders and corresponding files recursively.
37
-
38
- generate:
39
- generate dependence relationship for each file, this may accelarate
40
- `canoe buid` command. It's recommanded to execute this command everytime
41
- headers are added or removed from any file.
42
-
43
- update:
44
- this command is needed because '.canoe.deps' is actually a cache of dependency relationships so that canoe doesn't have to analyze all the files when building a project.
45
- So when a file includes new headers or some headers are removed, users have to use 'canoe udpate'
46
- to update dependency relationships.
47
-
48
- build [options]:
49
- build current project, arguments in [options] will be passed to C++ compiler
12
+ canoe update: udpate dependency relationships and store it in '.canoe.deps' file.
50
13
 
51
- run [options]:
52
- build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
53
-
54
- clean:
55
- remove all generated object files and binary files
56
-
57
- help:
58
- show this help message
59
-
60
- verion:
61
- display version information
62
-
63
- dep:
64
- display file dependencies in a better readable way
65
-
66
- @author: written by XIONG Ziwei, ICT, CAS
67
- @contact: noahxiong@outlook.com
68
- INFO
14
+ canoe run: compile and execute current project (execute this command in project directory)
15
+
16
+ canoe clean: remove all generated object files and binary files
17
+
18
+ canoe help: show this help message
19
+
20
+ canoe add tada: add a folder named tada under workspace/components,
21
+
22
+ canoe dep: show current dependency relationships of current project
23
+
24
+ canoe verion: version information
25
+
26
+ canoe make: generate a makefile for this project
27
+
28
+ new project_name [mode] [suffixes]:
29
+ create a new project with project_name.
30
+ In this project, four directories obj, src, target and third-party will be generated in project directory.
31
+ in src, directory 'components' will be generated if [mode] is '--lib', an extra main.cpp will be generated if [mode] is '--bin'
32
+
33
+ [mode]: --lib for a library and --bin for executable binaries
34
+ [suffixes]: should be in 'source_suffix:header_suffix" format, notice the ':' between two suffixes
35
+ add component_name:
36
+ add a folder named tada under workspace/components.
37
+ two files tada.hpp and tada.cpp would be craeted and intialized. File suffix may differ according users' specifications.
38
+ if component_name is a path separated by '/', then canoe would create folders and corresponding files recursively.
39
+
40
+ generate:
41
+ generate dependence relationship for each file, this may accelarate
42
+ `canoe buid` command. It's recommanded to execute this command everytime
43
+ headers are added or removed from any file.
44
+
45
+ update:
46
+ this command is needed because '.canoe.deps' is actually a cache of dependency relationships so that canoe doesn't have to analyze all the files when building a project.
47
+ So when a file includes new headers or some headers are removed, users have to use 'canoe udpate'
48
+ to update dependency relationships.
49
+
50
+ build [options]:
51
+ build current project, arguments in [options] will be passed to C++ compiler
52
+
53
+ run [options]:
54
+ build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
55
+
56
+ clean:
57
+ remove all generated object files and binary files
58
+
59
+ help:
60
+ show this help message
61
+
62
+ verion:
63
+ display version information
64
+
65
+ dep:
66
+ display file dependencies in a better readable way
67
+
68
+ make:
69
+ generate a Makefile for this project
70
+
71
+ @author: written by XIONG Ziwei, ICT, CAS
72
+ @contact: noahxiong@outlook.com
73
+ INFO
69
74
  puts info
70
75
  end
71
- end
76
+ end
@@ -0,0 +1,232 @@
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
11
+
12
+ def configure(config)
13
+ @config = config
14
+ end
15
+
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)
22
+ end
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def get_compiler
29
+ @config["compiler"]
30
+ end
31
+
32
+ def get_header_suffix
33
+ @workspace.header_suffix
34
+ end
35
+
36
+ def get_source_suffix
37
+ @workspace.source_suffix
38
+ end
39
+
40
+ def get_compiling_flags
41
+ flags = @config["flags"]["compile"].values.join " "
42
+ flags + " -I./src/components"
43
+ end
44
+
45
+ def get_ldflags
46
+ @config["flags"]["link"].values.select { |v| v.start_with?("-L") }.join " "
47
+ end
48
+
49
+ def get_ldlibs
50
+ (@config["flags"]["link"].values - (get_ldflags.split)).join " "
51
+ end
52
+
53
+ def cxx?(name)
54
+ return get_compiler.end_with? "++"
55
+ end
56
+
57
+ def make_cxx(makefile, deps)
58
+ make_common(makefile, "CXX", deps)
59
+ end
60
+
61
+ def make_c(makefile, deps)
62
+ make_common(makefile, "CC", deps)
63
+ end
64
+
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
+
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
78
+
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
91
+
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], ".*")
97
+ end
98
+ end
99
+
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"
107
+ end
108
+ end
109
+
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
123
+
124
+ def define_srcs(makefile, files)
125
+ @src_variables.each do |k, v|
126
+ makefile.puts("SRC_#{k}=#{v}")
127
+ end
128
+ end
129
+
130
+ def define_hdrs(makefile, files)
131
+ @hdr_variables.each do |k, v|
132
+ next if k == "MAIN"
133
+ makefile.puts("HDR_#{k}=#{v}")
134
+ end
135
+ end
136
+
137
+ def define_objs(makefile, files)
138
+ @obj_variables.each do |k, v|
139
+ makefile.puts("OBJ_#{k}=#{v}")
140
+ end
141
+ objs = @obj_variables.keys.map { |k| "$(OBJ_#{k})" }.join " "
142
+ makefile.puts("OBJS=#{objs}")
143
+ makefile.puts ""
144
+ end
145
+
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)
154
+ end
155
+ tmp
156
+ end
157
+ end
158
+
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)
163
+ else
164
+ "$(#{n}_DEP)"
165
+ end
166
+ end.flatten.join " "
167
+ makefile.puts("#{name}_DEP=#{as_str}")
168
+ end
169
+
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
176
+ end
177
+
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
183
+ end
184
+ dep_variables[k] = v
185
+ end
186
+
187
+ dep_variables.each do |k, v|
188
+ emit_dependencies(makefile, k, v)
189
+ end
190
+ end
191
+
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 ""
201
+ end
202
+
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)")
207
+ end
208
+ makefile.puts ""
209
+
210
+ clean = <<~DOC
211
+ .PHONY: clean
212
+ clean:
213
+ \trm $(TARGET)
214
+ \trm ./obj/*.o
215
+ DOC
216
+ makefile.puts(clean)
217
+ end
218
+ end
219
+
220
+ class WorkSpace
221
+ def make
222
+ config = ConfigReader.extract_flags "config.json"
223
+
224
+ deps = File.exist?(@deps) ?
225
+ DepAnalyzer.read_from(@deps) :
226
+ DepAnalyzer.new("./src").build_to_fil
227
+
228
+ makefile = Makefile.new(self)
229
+ makefile.configure(config)
230
+ makefile.make!(deps)
231
+ end
232
+ end
data/lib/workspace/new.rb CHANGED
@@ -9,14 +9,14 @@ class WorkSpace
9
9
  Dir.mkdir(@components)
10
10
  Dir.mkdir("#{@workspace}/obj")
11
11
  if @mode == :bin
12
- DefaultFiles.create_main(@src, @source_suffix)
12
+ DefaultFiles.create_main(@src, @source_suffix)
13
13
  else
14
14
  DefaultFiles.create_lib_header(@src, @name, @header_suffix)
15
15
  end
16
16
  File.new("#{@workspace}/.canoe", "w")
17
17
  DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
18
18
  # DefaultFiles.create_emacs_dir_local @workspace
19
-
19
+
20
20
  Dir.mkdir(@third)
21
21
  Dir.mkdir(@target)
22
22
  Dir.mkdir(@tests)
@@ -25,4 +25,4 @@ class WorkSpace
25
25
  end
26
26
  puts "workspace #{@workspace.blue} is created"
27
27
  end
28
- end
28
+ end
data/lib/workspace/run.rb CHANGED
@@ -6,4 +6,4 @@ class WorkSpace
6
6
  puts "./target/#{@name} #{args}"
7
7
  exec "./target/#{@name} #{args}"
8
8
  end
9
- end
9
+ end
@@ -1,5 +1,6 @@
1
1
  class WorkSpace
2
- public
2
+ public
3
+
3
4
  def test(args)
4
5
  if args.empty?
5
6
  test_all
@@ -11,12 +12,13 @@ public
11
12
  when "all"
12
13
  test_all
13
14
  else
14
- test_single arg
15
+ test_single arg
15
16
  end
16
17
  end
17
18
  end
18
19
 
19
- private
20
+ private
21
+
20
22
  def test_all
21
23
  puts "tests all"
22
24
  end
@@ -25,7 +27,7 @@ private
25
27
  puts "#{@tests}/bin/test_#{name}"
26
28
  # system "./#{@tests}/bin/test_#{name}"
27
29
  end
28
-
30
+
29
31
  ##
30
32
  # how to build:
31
33
  # each test file tests one or more components, indicated by included headers
@@ -33,7 +35,7 @@ private
33
35
  # TODO
34
36
  def build_test
35
37
  build
36
- deps = DepAnalyzer.new('./tests').build_to_file(['./src', './src/components', './tests', './tests/common'], './tests/.canoe.deps')
38
+ deps = DepAnalyzer.new("./tests").build_to_file(["./src", "./src/components", "./tests", "./tests/common"], "./tests/.canoe.deps")
37
39
  puts deps
38
40
  end
39
- end
41
+ end
@@ -2,4 +2,4 @@ class WorkSpace
2
2
  def update
3
3
  generate
4
4
  end
5
- end
5
+ end
@@ -1,20 +1,19 @@
1
- require 'fileutils'
2
- require_relative '../source_files'
3
- require_relative '../compiler'
4
- require_relative '../config_reader'
5
- require_relative '../default_files'
6
- require_relative '../err'
7
- require_relative '../dependence'
8
- require_relative '../coloring'
9
-
1
+ require "fileutils"
2
+ require_relative "../source_files"
3
+ require_relative "../compiler"
4
+ require_relative "../config_reader"
5
+ require_relative "../default_files"
6
+ require_relative "../err"
7
+ require_relative "../dependence"
8
+ require_relative "../coloring"
10
9
 
11
10
  class WorkSpace
12
11
  include Err
13
- attr_reader :name, :cwd
12
+ attr_reader :name, :cwd, :src_prefix, :components_prefix, :obj_prefix, :source_suffix, :header_suffix, :mode
14
13
 
15
- def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
14
+ def initialize(name, mode, src_suffix = "cpp", hdr_suffix = "hpp")
16
15
  @name = name
17
- @compiler = Compiler.new 'clang++', ['-Isrc/components'], []
16
+ @compiler = Compiler.new "clang++", ["-Isrc/components"], []
18
17
  @cwd = Dir.new(Dir.pwd)
19
18
  @workspace = "#{Dir.pwd}/#{@name}"
20
19
  @src = "#{@workspace}/src"
@@ -24,30 +23,30 @@ class WorkSpace
24
23
  @target = "#{@workspace}/target"
25
24
  @tests = "#{@workspace}/tests"
26
25
  @mode = mode
27
- @deps = '.canoe.deps'
26
+ @deps = ".canoe.deps"
28
27
 
29
- @src_prefix = './src/'
30
- @components_prefix = './src/components/'
31
- @obj_prefix = './obj/'
28
+ @src_prefix = "./src/"
29
+ @components_prefix = "./src/components/"
30
+ @obj_prefix = "./obj/"
32
31
 
33
32
  @source_suffix = src_suffix
34
33
  @header_suffix = hdr_suffix
35
34
  end
36
35
 
37
- def inspect
36
+ def inspect
38
37
  puts "name is #{@name}"
39
38
  puts "name is #{@workspace}"
40
39
  end
41
40
  end
42
41
 
43
- require_relative 'help'
44
- require_relative 'new'
45
- require_relative 'add'
46
- require_relative 'build'
47
- require_relative 'generate'
48
- require_relative 'run'
49
- require_relative 'dep'
50
- require_relative 'clean'
51
- require_relative 'version'
52
- require_relative 'update'
53
- require_relative 'test'
42
+ require_relative "help"
43
+ require_relative "new"
44
+ require_relative "add"
45
+ require_relative "build"
46
+ require_relative "generate"
47
+ require_relative "run"
48
+ require_relative "dep"
49
+ require_relative "clean"
50
+ require_relative "update"
51
+ require_relative "test"
52
+ require_relative "make"
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.0.2
4
+ version: 0.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - XIONG Ziwei
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-09-06 00:00:00.000000000 Z
11
+ date: 2021-02-15 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: |+
14
14
  Canoe offers project management and building facilities to C/C++ projects.
@@ -41,11 +41,11 @@ files:
41
41
  - lib/workspace/dep.rb
42
42
  - lib/workspace/generate.rb
43
43
  - lib/workspace/help.rb
44
+ - lib/workspace/make.rb
44
45
  - lib/workspace/new.rb
45
46
  - lib/workspace/run.rb
46
47
  - lib/workspace/test.rb
47
48
  - lib/workspace/update.rb
48
- - lib/workspace/version.rb
49
49
  - lib/workspace/workspace.rb
50
50
  homepage: https://github.com/Dicridon/canoe
51
51
  licenses:
@@ -1,13 +0,0 @@
1
- class WorkSpace
2
- def version
3
- puts <<~VER
4
- canoe v0.3.0.2
5
- For features in this version, please visit https://github.com/Dicridon/canoe
6
- Currently, canoe can do below:
7
- - project creation
8
- - project auto build and run (works like Cargo for Rust)
9
- - project structure management
10
- by XIONG Ziwei
11
- VER
12
- end
13
- end