]> git.tdb.fi Git - builder.git/blob - source/filetarget.cpp
Replace basic for loops with range-based loops or algorithms
[builder.git] / source / filetarget.cpp
1 #include <msp/core/algorithm.h>
2 #include <msp/fs/stat.h>
3 #include <msp/fs/utils.h>
4 #include <msp/strings/format.h>
5 #include <msp/strings/utils.h>
6 #include <msp/time/utils.h>
7 #include "builder.h"
8 #include "filetarget.h"
9 #include "sourcepackage.h"
10 #include "task.h"
11 #include "tool.h"
12
13 using namespace std;
14 using namespace Msp;
15
16 FileTarget::FileTarget(Builder &b, const FS::Path &a):
17         Target(b, generate_name(b, 0, a)),
18         path(a)
19 {
20         init(0);
21 }
22
23 FileTarget::FileTarget(Builder &b, const SourcePackage &p, const FS::Path &a):
24         Target(b, generate_name(b, &p, a)),
25         path(a)
26 {
27         init(&p);
28 }
29
30 void FileTarget::init(const SourcePackage *p)
31 {
32         size = 0;
33         package = p;
34         nested_build_sig = false;
35         arch_in_build_sig = false;
36
37         builder.get_vfs().register_path(path, this);
38
39         stat();
40 }
41
42 void FileTarget::stat()
43 {
44         if(FS::Stat st = FS::lstat(path))
45         {
46                 mtime = st.get_modify_time();
47                 size = st.get_size();
48         }
49 }
50
51 string FileTarget::generate_name(Builder &builder, const SourcePackage *pkg, const FS::Path &path)
52 {
53         if(pkg && FS::descendant_depth(path, pkg->get_source_directory())>=0)
54         {
55                 FS::Path relpath = FS::relative(path, pkg->get_source_directory());
56                 return format("<%s>%s", pkg->get_name(), relpath.str().substr(1));
57         }
58         else if(FS::descendant_depth(path, builder.get_prefix())>=0)
59         {
60                 FS::Path relpath = FS::relative(path, builder.get_prefix());
61                 return "<prefix>"+relpath.str().substr(1);
62         }
63
64         return path.str();
65 }
66
67 void FileTarget::touch()
68 {
69         mtime = Time::now();
70         modified();
71         signal_bubble_rebuild.emit();
72 }
73
74 void FileTarget::check_rebuild()
75 {
76         if(!tool || needs_rebuild())
77                 return;
78
79         if(!mtime)
80                 mark_rebuild("Does not exist");
81         else
82         {
83                 for(Target *d: depends)
84                 {
85                         FileTarget *ft = dynamic_cast<FileTarget *>(d);
86                         if(ft && ft->get_mtime()>mtime)
87                                 mark_rebuild(d->get_name()+" has changed");
88                         else if(d->needs_rebuild())
89                                 mark_rebuild(d->get_name()+" needs rebuilding");
90                         if(needs_rebuild())
91                                 break;
92                 }
93         }
94
95         if(!needs_rebuild())
96         {
97                 // Some side effects might not exist
98                 auto i = find_if(side_effects, [](const Target *s){ return s->needs_rebuild(); });
99                 if(i!=side_effects.end())
100                         mark_rebuild((*i)->get_name()+" needs rebuilding");
101         }
102
103         if(!needs_rebuild() && package)
104         {
105                 if(package->get_config().get_mtime()>mtime)
106                         mark_rebuild("Package options changed");
107
108                 if(tool->get_executable())
109                 {
110                         string build_sig = create_build_signature();
111                         if(package->get_cache().has_key(this, "build_sig"))
112                         {
113                                 if(package->get_cache().get_value(this, "build_sig")!=build_sig)
114                                         mark_rebuild("Build signature changed");
115                         }
116                 }
117         }
118 }
119
120 string FileTarget::create_build_signature() const
121 {
122         if(!package)
123                 return string();
124
125         const BuildInfo &binfo = (component ? component->get_build_info() : package->get_build_info());
126         list<string> sigs;
127         if(nested_build_sig && component)
128         {
129                 set<const Tool *> depend_tools;
130                 for(Target *d: depends)
131                         if(d->get_component()==component && d->get_tool())
132                                 depend_tools.insert(d->get_tool());
133
134                 for(const Tool *t: depend_tools)
135                         sigs.push_back(t->create_build_signature(binfo));
136                 sigs.sort();
137                 sigs.push_front(tool->create_build_signature(binfo));
138         }
139         else
140                 sigs.push_back(tool->create_build_signature(binfo));
141
142         if(arch_in_build_sig)
143                 if(const Architecture *arch = tool->get_architecture())
144                         sigs.push_front(arch->get_name());
145
146         return join(sigs.begin(), sigs.end(), ";");
147 }
148
149 void FileTarget::build(Task &task)
150 {
151         task.add_file(path);
152         task.set_unlink(true);
153 }
154
155 void FileTarget::build_finished(bool success)
156 {
157         if(success)
158         {
159                 stat();
160                 if(package)
161                 {
162                         string build_sig = create_build_signature();
163                         if(!build_sig.empty())
164                                 package->get_cache().set_value(this, "build_sig", build_sig);
165                 }
166         }
167
168         Target::build_finished(success);
169 }
170
171 void FileTarget::clean()
172 {
173         if(mtime)
174         {
175                 FS::unlink(path);
176                 mtime = Time::TimeStamp();
177                 size = 0;
178                 check_rebuild();
179         }
180 }