canoe 0.2.2 → 0.3.0.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.
- checksums.yaml +4 -4
- data/bin/canoe +1 -0
- data/lib/canoe.rb +12 -2
- data/lib/cmd.rb +9 -2
- data/lib/coloring.rb +23 -0
- data/lib/compiler.rb +32 -12
- data/lib/config_reader.rb +3 -0
- data/lib/default_files.rb +84 -61
- data/lib/dependence.rb +40 -4
- data/lib/err.rb +4 -3
- data/lib/source_files.rb +3 -0
- data/lib/workspace/add.rb +26 -0
- data/lib/workspace/build.rb +130 -0
- data/lib/workspace/clean.rb +26 -0
- data/lib/workspace/dep.rb +12 -0
- data/lib/workspace/generate.rb +6 -0
- data/lib/workspace/help.rb +71 -0
- data/lib/workspace/new.rb +28 -0
- data/lib/workspace/run.rb +9 -0
- data/lib/workspace/test.rb +39 -0
- data/lib/workspace/update.rb +5 -0
- data/lib/workspace/version.rb +13 -0
- data/lib/workspace/workspace.rb +53 -0
- metadata +24 -7
- data/lib/workspace.rb +0 -272
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: acf64e52f86562fbb4103263adf6ac25d3583fdd8cc935df460d6df89ffa4367
|
|
4
|
+
data.tar.gz: 8f3e6ba476da88e1cd34abffb4bfa70e0ac910fb5bc93977601df49e44a75735
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: e39ce423d813c64ef43c4440990439463a99dcb724771adc2d4d5db130c8206d7a3801c9fd036ee1477cd5c162f19b3da3dbc123e6114cba5bc7d8c0bf7d03a0
|
|
7
|
+
data.tar.gz: fe49d0b455bb21deb30b149f08736e2cff7091d8a3d38f87ac395fa1800c8b9abdb7c17594007412f5aacce448da5ebb60fd9a986fbf2ab645737aa59cd9100f
|
data/bin/canoe
CHANGED
data/lib/canoe.rb
CHANGED
|
@@ -1,10 +1,20 @@
|
|
|
1
|
-
require_relative "workspace"
|
|
1
|
+
require_relative "workspace/workspace.rb"
|
|
2
2
|
require_relative "cmd"
|
|
3
3
|
require_relative "source_files"
|
|
4
4
|
|
|
5
5
|
class Canoe
|
|
6
6
|
def initialize
|
|
7
|
-
options = [
|
|
7
|
+
options = ['new',
|
|
8
|
+
'add',
|
|
9
|
+
'build',
|
|
10
|
+
'generate',
|
|
11
|
+
'run',
|
|
12
|
+
'dep',
|
|
13
|
+
'clean',
|
|
14
|
+
'version',
|
|
15
|
+
'help',
|
|
16
|
+
'update',
|
|
17
|
+
'test']
|
|
8
18
|
@cmd = CmdParser.new options
|
|
9
19
|
end
|
|
10
20
|
|
data/lib/cmd.rb
CHANGED
|
@@ -1,7 +1,10 @@
|
|
|
1
|
-
require_relative "workspace"
|
|
1
|
+
require_relative "workspace/workspace"
|
|
2
2
|
require_relative "err"
|
|
3
3
|
require_relative "config_reader"
|
|
4
4
|
|
|
5
|
+
##
|
|
6
|
+
# class CmdParser
|
|
7
|
+
# Parsing command arguments passed to canoe
|
|
5
8
|
class CmdParser
|
|
6
9
|
include Err
|
|
7
10
|
def initialize(options)
|
|
@@ -85,9 +88,13 @@ class CmdParser
|
|
|
85
88
|
get_current_workspace.clean
|
|
86
89
|
end
|
|
87
90
|
|
|
91
|
+
def parse_test(args)
|
|
92
|
+
get_current_workspace.test args
|
|
93
|
+
end
|
|
94
|
+
|
|
88
95
|
def parse_version(args)
|
|
89
96
|
puts <<~VER
|
|
90
|
-
canoe v0.2
|
|
97
|
+
canoe v0.3.0.2
|
|
91
98
|
For features in this version, please visit https://github.com/Dicridon/canoe
|
|
92
99
|
Currently, canoe can do below:
|
|
93
100
|
- project creation
|
data/lib/coloring.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
##
|
|
2
|
+
# gem Colorize is a great tool, but I don't want add dependencies to Canoe
|
|
3
|
+
class String
|
|
4
|
+
def self.define_coloring_methods
|
|
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
|
|
14
|
+
}
|
|
15
|
+
colors.each do |k, v|
|
|
16
|
+
define_method v do
|
|
17
|
+
"\033[#{k}m#{self}\033[0m"
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
define_coloring_methods
|
|
23
|
+
end
|
data/lib/compiler.rb
CHANGED
|
@@ -1,29 +1,49 @@
|
|
|
1
|
+
##
|
|
2
|
+
# class Compiler
|
|
3
|
+
# Storing compiler name in String and flags as an array
|
|
1
4
|
class Compiler
|
|
2
5
|
attr_reader :name, :flags
|
|
3
|
-
|
|
6
|
+
##
|
|
7
|
+
# @name: String
|
|
8
|
+
# @flgs: Array of String
|
|
9
|
+
def initialize(name, compiling_flags, linking_flags)
|
|
4
10
|
@name = name
|
|
5
|
-
@
|
|
11
|
+
@linking_flags = linking_flags
|
|
12
|
+
@compiling_flags = compiling_flags
|
|
6
13
|
end
|
|
7
14
|
|
|
8
|
-
def
|
|
9
|
-
|
|
15
|
+
def compiling_flags_as_str
|
|
16
|
+
@compiling_flags.join " "
|
|
10
17
|
end
|
|
11
18
|
|
|
12
|
-
def
|
|
13
|
-
@
|
|
19
|
+
def linking_flags_as_str
|
|
20
|
+
@linking_flags.join " "
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def append_compiling_flag(flag)
|
|
25
|
+
@compiling_flags << flag
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def append_linking_flag(flag)
|
|
29
|
+
@linking_flags << flag
|
|
14
30
|
end
|
|
15
31
|
|
|
16
32
|
def compile(src, out)
|
|
17
|
-
puts "#{name} -o #{out} #{
|
|
18
|
-
system "#{name} -o #{out} #{
|
|
33
|
+
puts "#{name} -o #{out} #{compiling_flags_as_str} -c #{src}"
|
|
34
|
+
system "#{name} -o #{out} #{compiling_flags_as_str} -c #{src}"
|
|
19
35
|
end
|
|
20
36
|
|
|
21
|
-
def
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
system "#{name} -o #{out} #{objs.join(" ")} #{libs.join(" ")}"
|
|
37
|
+
def link_executable(out, objs)
|
|
38
|
+
puts "#{name} -o #{out} #{objs.join(" ")} #{linking_flags_as_str}"
|
|
39
|
+
system "#{name} -o #{out} #{objs.join(" ")} #{linking_flags_as_str}"
|
|
25
40
|
end
|
|
26
41
|
|
|
42
|
+
def link_shared(out, objs)
|
|
43
|
+
puts "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
|
|
44
|
+
system "#{name} -shared -o #{out}.so #{objs.join(" ")} #{linking_flags_as_str}"
|
|
45
|
+
end
|
|
46
|
+
|
|
27
47
|
def inspect
|
|
28
48
|
puts "compiler name: #{name.inspect}"
|
|
29
49
|
puts "compiler flags: #{flags.inspect}"
|
data/lib/config_reader.rb
CHANGED
data/lib/default_files.rb
CHANGED
|
@@ -1,70 +1,93 @@
|
|
|
1
|
+
##
|
|
2
|
+
# class DefaultFiles
|
|
3
|
+
# A singleton class to generate header and souce files.
|
|
4
|
+
# TODO: consider using class source_file.rb in Pareater
|
|
1
5
|
class DefaultFiles
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
6
|
+
class << self
|
|
7
|
+
def open_file_and_write(filename, content)
|
|
8
|
+
File.open(filename, "w") do |f|
|
|
9
|
+
f.write(content)
|
|
10
|
+
end
|
|
11
|
+
end
|
|
7
12
|
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
13
|
+
def create_config(path, src_sfx='cpp', hdr_sfx='hpp')
|
|
14
|
+
open_file_and_write(
|
|
15
|
+
"#{path}/config.json",
|
|
16
|
+
<<~CONFIG
|
|
17
|
+
{
|
|
18
|
+
"compiler": "clang++",
|
|
19
|
+
"header-suffix": "#{hdr_sfx}",
|
|
20
|
+
"source-suffix": "#{src_sfx}",
|
|
21
|
+
"flags": {
|
|
22
|
+
"compile": {
|
|
23
|
+
"opt": "-O2",
|
|
24
|
+
"debug": "-g",
|
|
25
|
+
"std": "-std=c++17"
|
|
26
|
+
},
|
|
27
|
+
"link": {
|
|
28
|
+
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
CONFIG
|
|
33
|
+
)
|
|
34
|
+
end
|
|
25
35
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
36
|
+
def create_main(path, suffix='cpp')
|
|
37
|
+
open_file_and_write(
|
|
38
|
+
"#{path}/main.#{suffix}",
|
|
39
|
+
<<~DOC
|
|
40
|
+
#include <iostream>
|
|
41
|
+
int main(int argc, char *argv[]) {
|
|
42
|
+
std::cout << "hello world!" << std::endl;
|
|
43
|
+
}
|
|
44
|
+
DOC
|
|
45
|
+
)
|
|
46
|
+
end
|
|
37
47
|
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
48
|
+
def create_lib_header(path, lib_name, suffix='hpp')
|
|
49
|
+
open_file_and_write(
|
|
50
|
+
"#{path}/#{lib_name}.#{suffix}",
|
|
51
|
+
<<~DOC
|
|
52
|
+
#ifndef __#{lib_name.upcase}__
|
|
53
|
+
#define __#{lib_name.upcase}__
|
|
54
|
+
|
|
55
|
+
#endif
|
|
56
|
+
DOC
|
|
57
|
+
)
|
|
58
|
+
end
|
|
49
59
|
|
|
50
|
-
|
|
51
|
-
open_file_and_write(
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
60
|
+
# def create_emacs_dir_local(path)
|
|
61
|
+
# open_file_and_write(
|
|
62
|
+
# "#{path}/.dir-locals.el",
|
|
63
|
+
# <<~DOC
|
|
64
|
+
# ((nil . ((company-clang-arguments . ("-I./src/components/"
|
|
65
|
+
# "-I./components/"))))
|
|
66
|
+
# (nil . ((company-c-headers-path-user . ("./src/components/"
|
|
67
|
+
# "./components/")))))
|
|
68
|
+
# DOC
|
|
69
|
+
# )
|
|
70
|
+
# end
|
|
58
71
|
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
72
|
+
def create_cpp(filename, src_sfx='cpp', hdr_sfx='hpp')
|
|
73
|
+
open_file_and_write(
|
|
74
|
+
"#{filename}.#{src_sfx}",
|
|
75
|
+
<<~DOC
|
|
76
|
+
#include "#{filename}.#{hdr_sfx}"
|
|
77
|
+
DOC
|
|
78
|
+
)
|
|
79
|
+
end
|
|
65
80
|
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
81
|
+
def create_hpp(workspace, prefix, filename, hdr_sfx='hpp')
|
|
82
|
+
open_file_and_write(
|
|
83
|
+
"#{filename}.#{hdr_sfx}",
|
|
84
|
+
<<~DOC
|
|
85
|
+
#ifndef __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
|
|
86
|
+
#define __#{workspace.upcase}__#{prefix.upcase}__#{filename.upcase}__
|
|
87
|
+
|
|
88
|
+
#endif
|
|
89
|
+
DOC
|
|
90
|
+
)
|
|
91
|
+
end
|
|
69
92
|
end
|
|
70
93
|
end
|
data/lib/dependence.rb
CHANGED
|
@@ -1,6 +1,19 @@
|
|
|
1
1
|
require_relative 'source_files'
|
|
2
2
|
require_relative 'err'
|
|
3
3
|
|
|
4
|
+
##
|
|
5
|
+
# class DepAnalyzer
|
|
6
|
+
# This class is the key component of canoe, which offers file dependency analysis functionality.
|
|
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.
|
|
9
|
+
# DepAnalyzer would read every source file and recursively process user header files included in this source file to
|
|
10
|
+
# find out all user header files this source file depends on.
|
|
11
|
+
# Based on dependencies built in previous stage, DepAnalyzer determines which files should be recompiled and return
|
|
12
|
+
# these files to caller.
|
|
13
|
+
#
|
|
14
|
+
# Dependencies could be written to a file to avoid wasting time parsing all files, Depanalyzer would read from
|
|
15
|
+
# this file to construct dependencies. But if sources files included new headers or included headers are revmoed,
|
|
16
|
+
# Depanalyzer should rebuild the whole dependencies.
|
|
4
17
|
class DepAnalyzer
|
|
5
18
|
include Err
|
|
6
19
|
def self.read_from(filename)
|
|
@@ -16,16 +29,26 @@ class DepAnalyzer
|
|
|
16
29
|
end
|
|
17
30
|
|
|
18
31
|
def self.compiling_filter(deps, build_time, src_sfx='cpp', hdr_sfx='hpp')
|
|
19
|
-
files = []
|
|
32
|
+
files = []
|
|
33
|
+
@processed = {}
|
|
34
|
+
@recompiles = {}
|
|
35
|
+
deps.keys.each do |k|
|
|
36
|
+
@processed[k] = false
|
|
37
|
+
@recompiles[k] = false
|
|
38
|
+
end
|
|
20
39
|
deps.each do |k, v|
|
|
21
40
|
next if k.end_with? ".#{hdr_sfx}"
|
|
22
41
|
if should_recompile?(k, build_time)
|
|
23
42
|
files << k
|
|
43
|
+
@processed[k] = true
|
|
44
|
+
@recompiles[k] = true
|
|
24
45
|
next
|
|
25
46
|
end
|
|
26
47
|
v.each do |f|
|
|
27
48
|
if mark(f, build_time, deps) || mark(f.sub(".#{hdr_sfx}", ".#{src_sfx}"), build_time, deps)
|
|
28
49
|
files << k
|
|
50
|
+
@processed[k] = true
|
|
51
|
+
@recompiles[k] = true
|
|
29
52
|
break
|
|
30
53
|
end
|
|
31
54
|
end
|
|
@@ -35,21 +58,34 @@ class DepAnalyzer
|
|
|
35
58
|
|
|
36
59
|
private
|
|
37
60
|
def self.mark(file, build_time, deps)
|
|
61
|
+
ret = false
|
|
38
62
|
return false unless File.exists? file
|
|
39
63
|
if should_recompile?(file, build_time)
|
|
40
64
|
return true
|
|
41
65
|
else
|
|
42
66
|
deps[file].each do |f|
|
|
43
|
-
|
|
67
|
+
if @processed[f]
|
|
68
|
+
ret |= @recompiles[f]
|
|
69
|
+
next
|
|
70
|
+
end
|
|
71
|
+
@processed[f] = true
|
|
72
|
+
if mark(f, build_time, deps)
|
|
73
|
+
@recompiles[f] = true
|
|
74
|
+
return true
|
|
75
|
+
end
|
|
44
76
|
end
|
|
45
77
|
end
|
|
46
|
-
|
|
78
|
+
ret
|
|
47
79
|
end
|
|
48
80
|
|
|
49
81
|
def self.should_recompile?(file, build_time)
|
|
50
82
|
judge = build_time
|
|
51
83
|
if build_time == Time.new(0)
|
|
52
|
-
objfile =
|
|
84
|
+
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
|
|
53
89
|
return true unless File.exists? objfile
|
|
54
90
|
judge = File.mtime(objfile)
|
|
55
91
|
end
|
data/lib/err.rb
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
|
+
require_relative 'coloring'
|
|
1
2
|
module Err
|
|
2
3
|
def warn_on_err(err)
|
|
3
4
|
puts <<~ERR
|
|
4
|
-
|
|
5
|
+
#{"Waring: ".yellow}
|
|
5
6
|
#{err}
|
|
6
7
|
try 'canoe help' for more information
|
|
7
8
|
ERR
|
|
@@ -9,11 +10,11 @@ module Err
|
|
|
9
10
|
|
|
10
11
|
def abort_on_err(err)
|
|
11
12
|
abort <<~ERR
|
|
12
|
-
Fatal:
|
|
13
|
+
#{"Fatal: ".red}
|
|
13
14
|
#{err}
|
|
14
15
|
try 'canoe help' for more information
|
|
15
16
|
ERR
|
|
16
17
|
end
|
|
17
18
|
|
|
18
19
|
module_function :warn_on_err, :abort_on_err
|
|
19
|
-
end
|
|
20
|
+
end
|
data/lib/source_files.rb
CHANGED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
def add(args)
|
|
3
|
+
args.each do |i|
|
|
4
|
+
dir = @components
|
|
5
|
+
filenames = i.split("/")
|
|
6
|
+
prefix = []
|
|
7
|
+
filenames.each do |filename|
|
|
8
|
+
dir += "/#{filename}"
|
|
9
|
+
prefix << filename
|
|
10
|
+
unless Dir.exist? dir
|
|
11
|
+
FileUtils.mkdir dir
|
|
12
|
+
Dir.chdir(dir) do
|
|
13
|
+
puts "created " + Dir.pwd.blue
|
|
14
|
+
create_working_files prefix.join('__'), filename
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
private
|
|
22
|
+
def create_working_files(prefix, filename)
|
|
23
|
+
DefaultFiles.create_cpp filename, @source_suffix, @header_suffix
|
|
24
|
+
DefaultFiles.create_hpp @name, prefix, filename, @header_suffix
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
# args are commandline parameters passed to `canoe build`,
|
|
3
|
+
# could be 'all', 'test', 'target' or empty
|
|
4
|
+
def build(args)
|
|
5
|
+
case args[0]
|
|
6
|
+
when "all"
|
|
7
|
+
build_all
|
|
8
|
+
when "test"
|
|
9
|
+
build_test
|
|
10
|
+
else
|
|
11
|
+
build_target
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
private
|
|
16
|
+
def build_flags(flags, config)
|
|
17
|
+
config.values.each do |v|
|
|
18
|
+
case v
|
|
19
|
+
when String
|
|
20
|
+
flags << v
|
|
21
|
+
when Array
|
|
22
|
+
v.each do |o|
|
|
23
|
+
flags << o
|
|
24
|
+
end
|
|
25
|
+
else
|
|
26
|
+
abort_on_err "unknown options in config.json, #{v}"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def build_compiler_from_config
|
|
32
|
+
Dir.chdir(@workspace) do
|
|
33
|
+
flags = ConfigReader.extract_flags "config.json"
|
|
34
|
+
compiler_name = flags['compiler'] ? flags['compiler'] : "clang++"
|
|
35
|
+
abort_on_err "compiler #{compiler_name} not found" unless File.exists?("/usr/bin/#{compiler_name}")
|
|
36
|
+
compiler_flags = ['-Isrc/components']
|
|
37
|
+
linker_flags = []
|
|
38
|
+
|
|
39
|
+
c_flags, l_flags = flags['flags']['compile'], flags['flags']['link']
|
|
40
|
+
build_flags(compiler_flags, c_flags)
|
|
41
|
+
build_flags(linker_flags, l_flags)
|
|
42
|
+
|
|
43
|
+
@compiler = Compiler.new compiler_name, compiler_flags, linker_flags
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def compile(f, o)
|
|
48
|
+
@compiler.compile f, o
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
def link_exectutable(odir, objs)
|
|
52
|
+
puts "#{"[100%]".green} linking"
|
|
53
|
+
@compiler.link_executable "#{odir}/#{@name}", objs
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def link_shared(odir, objs)
|
|
57
|
+
puts "#{"[100%]".green} linking"
|
|
58
|
+
@compiler.link_shared "#{odir}/lib#{@name}", objs
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def build_bin(files)
|
|
62
|
+
# return if files.empty?
|
|
63
|
+
build_compiler_from_config
|
|
64
|
+
if build_common(files) && link_exectutable('./target', Dir.glob("obj/*.o"))
|
|
65
|
+
puts "BUILDING SUCCEEDED".green
|
|
66
|
+
else
|
|
67
|
+
puts "building FAILED".red
|
|
68
|
+
end
|
|
69
|
+
end
|
|
70
|
+
|
|
71
|
+
def build_lib(files)
|
|
72
|
+
# return if files.empty?
|
|
73
|
+
build_compiler_from_config
|
|
74
|
+
@compiler.append_compiling_flag '-fPIC'
|
|
75
|
+
if build_common(files) && link_shared('./target', Dir.glob("obj/*.o"))
|
|
76
|
+
puts "BUILDING SUCCEEDED".green
|
|
77
|
+
else
|
|
78
|
+
puts "building FAILED".red
|
|
79
|
+
end
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def build_common(files)
|
|
83
|
+
all = SourceFiles.get_all('./src') {|f| f.end_with? @source_suffix}
|
|
84
|
+
total = all.size.to_f
|
|
85
|
+
compiled = total - files.size
|
|
86
|
+
comps = files.select {|f| f.start_with? @components_prefix}
|
|
87
|
+
srcs = files - comps
|
|
88
|
+
flag = true;
|
|
89
|
+
|
|
90
|
+
srcs.each do |f|
|
|
91
|
+
progress = (compiled / total).round(2) * 100
|
|
92
|
+
printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
|
|
93
|
+
fname = f.split("/")[-1]
|
|
94
|
+
o = @obj_prefix + File.basename(fname, ".*") + '.o'
|
|
95
|
+
flag = false unless compile f, o
|
|
96
|
+
compiled += 1
|
|
97
|
+
end
|
|
98
|
+
|
|
99
|
+
comps.each do |f|
|
|
100
|
+
progress = (compiled / total).round(2) * 100
|
|
101
|
+
printf "[#{progress.to_i}%%]".green + " compiling #{f}: "
|
|
102
|
+
o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
|
|
103
|
+
.gsub('/', '_') + '.o'
|
|
104
|
+
flag = false unless compile f, o
|
|
105
|
+
compiled += 1
|
|
106
|
+
end
|
|
107
|
+
flag
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
def build_all
|
|
111
|
+
build_target
|
|
112
|
+
build_test
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
def build_target
|
|
116
|
+
deps = File.exist?(@deps) ?
|
|
117
|
+
DepAnalyzer.read_from(@deps) :
|
|
118
|
+
DepAnalyzer.new('./src').build_to_file(['./src', './src/components'], @deps)
|
|
119
|
+
target = "./target/#{@name}"
|
|
120
|
+
build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
|
|
121
|
+
files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
|
|
122
|
+
|
|
123
|
+
if files.empty? && File.exist?(target)
|
|
124
|
+
puts "nothing to do, all up to date"
|
|
125
|
+
return
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
self.send "build_#{@mode.to_s}", files
|
|
129
|
+
end
|
|
130
|
+
end
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
def clean
|
|
3
|
+
self.send "clean_#{@mode.to_s}"
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
private
|
|
7
|
+
def clean_obj
|
|
8
|
+
puts "rm -f ./obj/*.o"
|
|
9
|
+
system "rm -f ./obj/*.o"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def clean_target
|
|
13
|
+
puts "rm -f ./target/*"
|
|
14
|
+
system "rm -f ./target/*"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def clean_bin
|
|
18
|
+
clean_obj
|
|
19
|
+
clean_target
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def clean_lib
|
|
23
|
+
clean_obj
|
|
24
|
+
clean_target
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
def self.help
|
|
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
|
|
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
|
|
50
|
+
|
|
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
|
|
69
|
+
puts info
|
|
70
|
+
end
|
|
71
|
+
end
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
def new
|
|
3
|
+
begin
|
|
4
|
+
Dir.mkdir(@name)
|
|
5
|
+
rescue
|
|
6
|
+
abort_on_err "workspace #{@name} already exsits"
|
|
7
|
+
end
|
|
8
|
+
Dir.mkdir(@src)
|
|
9
|
+
Dir.mkdir(@components)
|
|
10
|
+
Dir.mkdir("#{@workspace}/obj")
|
|
11
|
+
if @mode == :bin
|
|
12
|
+
DefaultFiles.create_main(@src, @source_suffix)
|
|
13
|
+
else
|
|
14
|
+
DefaultFiles.create_lib_header(@src, @name, @header_suffix)
|
|
15
|
+
end
|
|
16
|
+
File.new("#{@workspace}/.canoe", "w")
|
|
17
|
+
DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
|
|
18
|
+
# DefaultFiles.create_emacs_dir_local @workspace
|
|
19
|
+
|
|
20
|
+
Dir.mkdir(@third)
|
|
21
|
+
Dir.mkdir(@target)
|
|
22
|
+
Dir.mkdir(@tests)
|
|
23
|
+
Dir.chdir(@workspace) do
|
|
24
|
+
system "git init"
|
|
25
|
+
end
|
|
26
|
+
puts "workspace #{@workspace.blue} is created"
|
|
27
|
+
end
|
|
28
|
+
end
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
class WorkSpace
|
|
2
|
+
public
|
|
3
|
+
def test(args)
|
|
4
|
+
if args.empty?
|
|
5
|
+
test_all
|
|
6
|
+
return
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
args.each do |arg|
|
|
10
|
+
case arg
|
|
11
|
+
when "all"
|
|
12
|
+
test_all
|
|
13
|
+
else
|
|
14
|
+
test_single arg
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
private
|
|
20
|
+
def test_all
|
|
21
|
+
puts "tests all"
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def test_single(name)
|
|
25
|
+
puts "#{@tests}/bin/test_#{name}"
|
|
26
|
+
# system "./#{@tests}/bin/test_#{name}"
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
##
|
|
30
|
+
# how to build:
|
|
31
|
+
# each test file tests one or more components, indicated by included headers
|
|
32
|
+
# find corresponding object file in ../obj and link them to test file
|
|
33
|
+
# TODO
|
|
34
|
+
def build_test
|
|
35
|
+
build
|
|
36
|
+
deps = DepAnalyzer.new('./tests').build_to_file(['./src', './src/components', './tests', './tests/common'], './tests/.canoe.deps')
|
|
37
|
+
puts deps
|
|
38
|
+
end
|
|
39
|
+
end
|
|
@@ -0,0 +1,13 @@
|
|
|
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
|
|
@@ -0,0 +1,53 @@
|
|
|
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
|
+
|
|
10
|
+
|
|
11
|
+
class WorkSpace
|
|
12
|
+
include Err
|
|
13
|
+
attr_reader :name, :cwd
|
|
14
|
+
|
|
15
|
+
def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
|
|
16
|
+
@name = name
|
|
17
|
+
@compiler = Compiler.new 'clang++', ['-Isrc/components'], []
|
|
18
|
+
@cwd = Dir.new(Dir.pwd)
|
|
19
|
+
@workspace = "#{Dir.pwd}/#{@name}"
|
|
20
|
+
@src = "#{@workspace}/src"
|
|
21
|
+
@components = "#{@src}/components"
|
|
22
|
+
@obj = "#{@workspace}/obj"
|
|
23
|
+
@third = "#{@workspace}/third-party"
|
|
24
|
+
@target = "#{@workspace}/target"
|
|
25
|
+
@tests = "#{@workspace}/tests"
|
|
26
|
+
@mode = mode
|
|
27
|
+
@deps = '.canoe.deps'
|
|
28
|
+
|
|
29
|
+
@src_prefix = './src/'
|
|
30
|
+
@components_prefix = './src/components/'
|
|
31
|
+
@obj_prefix = './obj/'
|
|
32
|
+
|
|
33
|
+
@source_suffix = src_suffix
|
|
34
|
+
@header_suffix = hdr_suffix
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
def inspect
|
|
38
|
+
puts "name is #{@name}"
|
|
39
|
+
puts "name is #{@workspace}"
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
|
|
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'
|
metadata
CHANGED
|
@@ -1,19 +1,24 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: canoe
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.3.0.2
|
|
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-06
|
|
11
|
+
date: 2020-09-06 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
|
-
description:
|
|
14
|
-
|
|
13
|
+
description: |+
|
|
14
|
+
Canoe offers project management and building facilities to C/C++ projects.
|
|
15
|
+
|
|
16
|
+
If you are tired of writing Makefile, CMakeList and even SConstruct, please let Canoe help you wipe them out.
|
|
17
|
+
|
|
15
18
|
Similar to Cargo for Rust, Canoe offers commands such as new, build, run, etc. to help you generate a C/C++ project and build it automatically.
|
|
16
|
-
|
|
19
|
+
|
|
20
|
+
Different from tools like Scons and Blade, Canoe requires users to write NO building scripts, Canoe would analyze dependencies and build like our old friend 'make' if a few conventions over file names are followed.
|
|
21
|
+
|
|
17
22
|
email: noahxiong@outlook.com
|
|
18
23
|
executables:
|
|
19
24
|
- canoe
|
|
@@ -23,13 +28,25 @@ files:
|
|
|
23
28
|
- bin/canoe
|
|
24
29
|
- lib/canoe.rb
|
|
25
30
|
- lib/cmd.rb
|
|
31
|
+
- lib/coloring.rb
|
|
26
32
|
- lib/compiler.rb
|
|
27
33
|
- lib/config_reader.rb
|
|
28
34
|
- lib/default_files.rb
|
|
29
35
|
- lib/dependence.rb
|
|
30
36
|
- lib/err.rb
|
|
31
37
|
- lib/source_files.rb
|
|
32
|
-
- lib/workspace.rb
|
|
38
|
+
- lib/workspace/add.rb
|
|
39
|
+
- lib/workspace/build.rb
|
|
40
|
+
- lib/workspace/clean.rb
|
|
41
|
+
- lib/workspace/dep.rb
|
|
42
|
+
- lib/workspace/generate.rb
|
|
43
|
+
- lib/workspace/help.rb
|
|
44
|
+
- lib/workspace/new.rb
|
|
45
|
+
- lib/workspace/run.rb
|
|
46
|
+
- lib/workspace/test.rb
|
|
47
|
+
- lib/workspace/update.rb
|
|
48
|
+
- lib/workspace/version.rb
|
|
49
|
+
- lib/workspace/workspace.rb
|
|
33
50
|
homepage: https://github.com/Dicridon/canoe
|
|
34
51
|
licenses:
|
|
35
52
|
- MIT
|
|
@@ -52,5 +69,5 @@ requirements: []
|
|
|
52
69
|
rubygems_version: 3.1.2
|
|
53
70
|
signing_key:
|
|
54
71
|
specification_version: 4
|
|
55
|
-
summary: a C/C++ project management and
|
|
72
|
+
summary: a C/C++ project management and building tool
|
|
56
73
|
test_files: []
|
data/lib/workspace.rb
DELETED
|
@@ -1,272 +0,0 @@
|
|
|
1
|
-
require 'fileutils'
|
|
2
|
-
require 'open3'
|
|
3
|
-
require_relative 'source_files'
|
|
4
|
-
require_relative 'compiler'
|
|
5
|
-
require_relative 'config_reader'
|
|
6
|
-
require_relative 'default_files'
|
|
7
|
-
require_relative 'err'
|
|
8
|
-
require_relative 'dependence'
|
|
9
|
-
|
|
10
|
-
class WorkSpace
|
|
11
|
-
include Err
|
|
12
|
-
attr_reader :name, :cwd
|
|
13
|
-
def self.help
|
|
14
|
-
info = <<~INFO
|
|
15
|
-
canoe is a C/C++ project manager, inspired by Rust cargo.
|
|
16
|
-
usage:
|
|
17
|
-
canoe new tada: create a project named 'tada' in current directory
|
|
18
|
-
|
|
19
|
-
canoe build: compile current project (execute this command in project directory)
|
|
20
|
-
|
|
21
|
-
canoe generate: generate dependency relationship and store it in '.canoe.deps'
|
|
22
|
-
|
|
23
|
-
canoe run: compile and execute current project (execute this command in project directory)
|
|
24
|
-
|
|
25
|
-
canoe clean: remove all generated object files and binary files
|
|
26
|
-
|
|
27
|
-
canoe help: show this help message
|
|
28
|
-
|
|
29
|
-
canoe add tada: add a folder named tada under workspace/components,
|
|
30
|
-
two files tada.hpp and tada.cpp would be craeted and intialized
|
|
31
|
-
|
|
32
|
-
canoe verion: version information
|
|
33
|
-
|
|
34
|
-
new project_name [mode] [suffixes]:
|
|
35
|
-
create a new project with project_name.
|
|
36
|
-
In this project, four directories obj, src, target and third-party will be generated in project directory.
|
|
37
|
-
in src, directory 'components' will be generated if [mode] is '--lib', an extra main.cpp will be generated if [mode] is '--bin'
|
|
38
|
-
|
|
39
|
-
[mode]: --lib for a library and --bin for executable binaries
|
|
40
|
-
[suffixes]: should be in 'source_suffix:header_suffix" format, notice the ':' between two suffixes
|
|
41
|
-
|
|
42
|
-
generate:
|
|
43
|
-
generate dependence relationship for each file, this may accelarate
|
|
44
|
-
`canoe buid` command. It's recommanded to execute this command everytime
|
|
45
|
-
headers are added or removed from any file.
|
|
46
|
-
|
|
47
|
-
build [options]:
|
|
48
|
-
build current project, arguments in [options] will be passed to C++ compiler
|
|
49
|
-
|
|
50
|
-
run [options]:
|
|
51
|
-
build current project with no specific compilation flags, and run this project, passing [options] as command line arguments to the binary
|
|
52
|
-
|
|
53
|
-
clean:
|
|
54
|
-
remove all generated object files and binary files
|
|
55
|
-
|
|
56
|
-
help:
|
|
57
|
-
show this help message
|
|
58
|
-
|
|
59
|
-
verion:
|
|
60
|
-
display version information
|
|
61
|
-
|
|
62
|
-
dep:
|
|
63
|
-
display file dependencies in a better readable way
|
|
64
|
-
|
|
65
|
-
@author: written by XIONG Ziwei, ICT, CAS
|
|
66
|
-
@contact: noahxiong@outlook.com
|
|
67
|
-
INFO
|
|
68
|
-
puts info
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
def initialize(name, mode, src_suffix='cpp', hdr_suffix='hpp')
|
|
73
|
-
@name = name
|
|
74
|
-
@compiler = Compiler.new 'clang++', '-Isrc/components'
|
|
75
|
-
@cwd = Dir.new(Dir.pwd)
|
|
76
|
-
@workspace = "#{Dir.pwd}/#{@name}"
|
|
77
|
-
@src = "#{@workspace}/src"
|
|
78
|
-
@components = "#{@src}/components"
|
|
79
|
-
@obj = "#{@workspace}/obj"
|
|
80
|
-
@third = "#{@workspace}/third-party"
|
|
81
|
-
@target = "#{@workspace}/target"
|
|
82
|
-
@mode = mode
|
|
83
|
-
@deps = '.canoe.deps'
|
|
84
|
-
|
|
85
|
-
@src_prefix = './src/'
|
|
86
|
-
@components_prefix = './src/components/'
|
|
87
|
-
@obj_prefix = './obj/'
|
|
88
|
-
|
|
89
|
-
@source_suffix = src_suffix
|
|
90
|
-
@header_suffix = hdr_suffix
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
def new
|
|
94
|
-
Dir.mkdir(@name)
|
|
95
|
-
Dir.mkdir(@src)
|
|
96
|
-
Dir.mkdir(@components)
|
|
97
|
-
Dir.mkdir("#{@workspace}/obj")
|
|
98
|
-
DefaultFiles.create_main(@src, @source_suffix) if @mode == :bin
|
|
99
|
-
File.new("#{@workspace}/.canoe", "w")
|
|
100
|
-
DefaultFiles.create_config @workspace, @source_suffix, @header_suffix
|
|
101
|
-
DefaultFiles.create_emacs_dir_local @workspace
|
|
102
|
-
|
|
103
|
-
Dir.mkdir(@third)
|
|
104
|
-
Dir.mkdir(@target)
|
|
105
|
-
puts "workspace #{@workspace} is created"
|
|
106
|
-
end
|
|
107
|
-
|
|
108
|
-
# args are commandline parameters passed to `canoe build`
|
|
109
|
-
def build(args)
|
|
110
|
-
deps = File.exist?(@deps) ?
|
|
111
|
-
DepAnalyzer.read_from(@deps) :
|
|
112
|
-
DepAnalyzer.new('./src').build_to_file(['./src', './src/components'], @deps)
|
|
113
|
-
target = "./target/#{@name}"
|
|
114
|
-
build_time = File.exist?(target) ? File.mtime(target) : Time.new(0)
|
|
115
|
-
files = DepAnalyzer.compiling_filter(deps, build_time, @source_suffix, @header_suffix)
|
|
116
|
-
|
|
117
|
-
if files.empty?
|
|
118
|
-
puts "nothing to do, all up to date"
|
|
119
|
-
return
|
|
120
|
-
end
|
|
121
|
-
|
|
122
|
-
self.send "build_#{@mode.to_s}", files, args
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
def generate
|
|
126
|
-
DepAnalyzer.new('./src', @source_suffix, @header_suffix)
|
|
127
|
-
.build_to_file ['./src', './src/components'], @deps
|
|
128
|
-
end
|
|
129
|
-
|
|
130
|
-
def update
|
|
131
|
-
generate
|
|
132
|
-
end
|
|
133
|
-
|
|
134
|
-
def clean
|
|
135
|
-
self.send "clean_#{@mode.to_s}"
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def run(args)
|
|
139
|
-
build []
|
|
140
|
-
args = args.join " "
|
|
141
|
-
puts "./target/#{@name} #{args}"
|
|
142
|
-
exec "./target/#{@name} #{args}"
|
|
143
|
-
end
|
|
144
|
-
|
|
145
|
-
def add(args)
|
|
146
|
-
args.each do |i|
|
|
147
|
-
dir = @components
|
|
148
|
-
filenames = i.split("/")
|
|
149
|
-
prefix = []
|
|
150
|
-
filenames.each do |filename|
|
|
151
|
-
dir += "/#{filename}"
|
|
152
|
-
prefix << filename
|
|
153
|
-
unless Dir.exist? dir
|
|
154
|
-
FileUtils.mkdir dir
|
|
155
|
-
Dir.chdir(dir) do
|
|
156
|
-
puts "created " + Dir.pwd
|
|
157
|
-
create_working_files prefix.join('__'), filename
|
|
158
|
-
end
|
|
159
|
-
end
|
|
160
|
-
end
|
|
161
|
-
end
|
|
162
|
-
end
|
|
163
|
-
|
|
164
|
-
def dep
|
|
165
|
-
deps = DepAnalyzer.read_from(@deps) if File.exist?(@deps)
|
|
166
|
-
deps.each do |k, v|
|
|
167
|
-
unless v.empty?
|
|
168
|
-
puts "#{k} depends on: "
|
|
169
|
-
v.each {|f| puts " #{f}"}
|
|
170
|
-
puts ""
|
|
171
|
-
end
|
|
172
|
-
end
|
|
173
|
-
end
|
|
174
|
-
|
|
175
|
-
private
|
|
176
|
-
def create_working_files(prefix, filename)
|
|
177
|
-
DefaultFiles.create_cpp filename, @source_suffix, @header_suffix
|
|
178
|
-
DefaultFiles.create_hpp @name, prefix, filename, @header_suffix
|
|
179
|
-
end
|
|
180
|
-
|
|
181
|
-
def build_compiler_from_config(args)
|
|
182
|
-
Dir.chdir(@workspace) do
|
|
183
|
-
flags = ConfigReader.extract_flags "config.json"
|
|
184
|
-
compiler_name = flags['compiler'] ? flags['compiler'] : "clang++"
|
|
185
|
-
abort_on_err "compiler #{compiler_name} not found" unless File.exists?("/usr/bin/#{compiler_name}")
|
|
186
|
-
compiler_flags = ['-Isrc/components'] + args
|
|
187
|
-
|
|
188
|
-
if opts = flags['flags']
|
|
189
|
-
opts.each do |k, v|
|
|
190
|
-
case v
|
|
191
|
-
when String
|
|
192
|
-
compiler_flags << v
|
|
193
|
-
when Array
|
|
194
|
-
v.each do |o|
|
|
195
|
-
compiler_flags << o
|
|
196
|
-
end
|
|
197
|
-
else
|
|
198
|
-
abort_on_err "unknown options in config.json, #{v}"
|
|
199
|
-
end
|
|
200
|
-
end
|
|
201
|
-
end
|
|
202
|
-
|
|
203
|
-
@compiler = Compiler.new compiler_name, compiler_flags
|
|
204
|
-
end
|
|
205
|
-
end
|
|
206
|
-
|
|
207
|
-
def compile(f, o)
|
|
208
|
-
@compiler.compile f, o
|
|
209
|
-
end
|
|
210
|
-
|
|
211
|
-
def link(odir, objs)
|
|
212
|
-
status = system "#{@compiler} -o #{odir}/#{@name} #{objs.join(" ")}"
|
|
213
|
-
unless status
|
|
214
|
-
puts "compilation failed"
|
|
215
|
-
return
|
|
216
|
-
end
|
|
217
|
-
|
|
218
|
-
@compiler.link "#{odir}/#{@name}", objs
|
|
219
|
-
end
|
|
220
|
-
|
|
221
|
-
def build_bin(files, args)
|
|
222
|
-
build_compiler_from_config args
|
|
223
|
-
comps = files.select {|f| f.start_with? @components_prefix}
|
|
224
|
-
srcs = files - comps
|
|
225
|
-
|
|
226
|
-
srcs.each do |f|
|
|
227
|
-
puts "compiling #{f}"
|
|
228
|
-
fname = f.split("/")[-1]
|
|
229
|
-
o = @obj_prefix + fname.delete_suffix(File.extname(fname)) + '.o'
|
|
230
|
-
compile f, o
|
|
231
|
-
end
|
|
232
|
-
|
|
233
|
-
comps.each do |f|
|
|
234
|
-
puts "compiling #{f}"
|
|
235
|
-
o = @obj_prefix + f.delete_suffix(File.extname(f))[@components_prefix.length..]
|
|
236
|
-
.gsub('/', '_') + '.o'
|
|
237
|
-
compile f, o
|
|
238
|
-
end
|
|
239
|
-
|
|
240
|
-
link('./target', Dir.glob("obj/*.o")) unless files.empty?
|
|
241
|
-
end
|
|
242
|
-
|
|
243
|
-
def build_lib
|
|
244
|
-
puts "build a lib"
|
|
245
|
-
end
|
|
246
|
-
|
|
247
|
-
def clean_obj
|
|
248
|
-
puts "rm -f ./obj/*.o"
|
|
249
|
-
system "rm -f ./obj/*.o"
|
|
250
|
-
end
|
|
251
|
-
|
|
252
|
-
def clean_target
|
|
253
|
-
puts "rm -f ./target/*"
|
|
254
|
-
system "rm -f ./target/*"
|
|
255
|
-
end
|
|
256
|
-
|
|
257
|
-
def clean_bin
|
|
258
|
-
clean_obj
|
|
259
|
-
clean_target
|
|
260
|
-
end
|
|
261
|
-
|
|
262
|
-
def clean_lib
|
|
263
|
-
clean_obj
|
|
264
|
-
clean_target
|
|
265
|
-
end
|
|
266
|
-
|
|
267
|
-
public
|
|
268
|
-
def inspect
|
|
269
|
-
puts "name is #{@name}"
|
|
270
|
-
puts "name is #{@workspace}"
|
|
271
|
-
end
|
|
272
|
-
end
|