-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathmain.cpp
More file actions
144 lines (140 loc) · 5.23 KB
/
main.cpp
File metadata and controls
144 lines (140 loc) · 5.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
#include <regex>
#include <iostream>
#include "test.h"
#include <unistd.h> //for close
#include <vector>
#include <iterator>
#include <set>
#include <map>
#include <algorithm>
#include <stdexcept>
#include <fstream>
#include <unistd.h>
#include "test.h"
#include "test2.h"
#include "nested.h" //this includes an inner file.
#include <fcntl.h> //for open
#include <sys/mman.h> //for mmap
#include <sys/stat.h> //for fstat
#include <thread> //to determine number of cores
#include "File.h"
#include "FileFactory.h"
#include "Buildfile.h"
using namespace std;
using Stat = struct stat;
bool operator <(const timespec& lhs, const timespec& rhs)
{
if (lhs.tv_sec == rhs.tv_sec)
return lhs.tv_nsec < rhs.tv_nsec;
else
return lhs.tv_sec < rhs.tv_sec;
}
bool should_recompile(const string& cpp_filename, const string& object_filename) {
try {
const ObjectFile& target = FileFactory::get().get_obj_file(object_filename);
const CppFile& maincpp = FileFactory::get().get_cpp_file(cpp_filename);
bool should_recompile = false;
if(target.get_statistics().st_mtimespec < maincpp.get_statistics().st_mtimespec) {
should_recompile = true;
}
else {
const set<string>& headers = maincpp.get_headers();
for(auto& name : headers) {
const CppFile& header = FileFactory::get().get_cpp_file(name);
if(target.get_statistics().st_mtimespec < header.get_statistics().st_mtimespec) {
should_recompile = true;
break;
}
}
}
return should_recompile;
} catch(runtime_error& e) {
return true;
}
}
pid_t run_process(const vector<string>& args) {
//turn std::string args to c string args
pid_t pid = fork();
if(pid) {
//print the command of the child process
copy(args.begin(), args.end(), ostream_iterator<const string&>(cout, " "));
cout << endl;
} else {
vector<char*> c_args{args.size()};
transform(args.begin(), args.end(), c_args.begin(), [](const string& s){return const_cast<char*>(s.c_str());});
c_args.push_back(nullptr); //null terminate the array
if(execvp(c_args[0], c_args.data()) == -1) {
cerr << "error opening subprocess: " << endl;
switch(errno) {
case ENOENT:
cerr << "does not exit" << endl;
break;
case ENOEXEC:
cerr << "cannot execute" << endl;
break;
case EFAULT:
cerr << "outside address space" << endl;
break;
case EACCES:
cerr << "execute permission denied" << endl;
break;
default:
cerr << "some other error" << endl;
break;
}
}
exit(0);
}
return pid;
}
int main(int argc, char**) {
//TODO: check if buildfile is more recent then executable. If so, recompile everything and relink everything
//TODO: expand buildfile syntax to include all cpps or all except these cpps, etc
//TODO: potentially introduce variables. Not sure if a good idea or not.
Buildfile buildfile;
const vector<string>& cpp = buildfile.get_cpp_filenames();
const vector<string>& objects = buildfile.get_object_filenames();
int cores = thread::hardware_concurrency();
cores = min(cores, static_cast<int>(cpp.size()));
cout << "using up to: " << cores << " processes at once" << endl;
set<pid_t> process_ids;
bool should_relink = false;
for(size_t i = 0; i < objects.size(); ++i) {
if(should_recompile(cpp[i], objects[i])) {
if(process_ids.size() == static_cast<size_t>(cores)) {
//if we are using the max amount of processes, wait for a child
//this should allow any child to finish at any time and just
//use that instead
int status = 0;
pid_t wpid = wait(&status);
if(WEXITSTATUS(status)) {
cerr << "status was: " << status << " aborting linking!" << endl;
return 1;
}
process_ids.erase(wpid);
}
process_ids.insert(run_process(buildfile.get_compile_command(cpp[i], objects[i])));
should_relink = true;
}
}
//This checks if the executable exists. If not, we have to relink
Stat exe_stat;
if(stat(buildfile.get_execuatable_name().c_str(), &exe_stat) == -1 && errno == ENOENT)
should_relink = true;
if(should_relink) {
//wait for all children to finish compiling the object files
pid_t wpid;
int status = 0;
while ((wpid = wait(&status)) > 0) {
if(WEXITSTATUS(status)) {
cerr << "status was: " << status << " aborting linking!" << endl;
return 1;
}
}
cout << buildfile.get_link_command(objects) << endl;
system(buildfile.get_link_command(objects).c_str());
if(!buildfile.get_postlink_command().empty() && !--argc)
system(buildfile.get_postlink_command().c_str());
return 0;
}
}