1 using System;
2 using System.IO;
3 using System.Collections;
4 using cmsx.object;
5
6 public nothrow const char* Version()
7 {
8 return "4.0.0";
9 }
10
11 void PrintHelp()
12 {
13 Console.Out() << "Cmajor System X Linker version " << Version() << endl();
14 Console.Out() << "Usage: cmsxlink [options] { file.o | file.a }" << endl();
15 Console.Out() << "Options:" << endl();
16 Console.Out() << "--help (-h)" << endl();
17 Console.Out() << " Print help." << endl();
18 Console.Out() << "--verbose (-v)" << endl();
19 Console.Out() << " Be verbose." << endl();
20 Console.Out() << "--out=FILE (-o=FILE)" << endl();
21 Console.Out() << " Set output file name to FILE." << endl();
22 Console.Out() << " Default is 'a.out'." << endl();
23 Console.Out() << "--clsid=FILE (-c=FILE)" << endl();
24 Console.Out() << " Read class id's from FILE." << endl();
25 Console.Out() << "--min-stack-size=MINSTACKSIZE (-m=MINSTACKSIZE)" << endl();
26 Console.Out() << " Set minimum size stack size to MINSTACKSIZE bytes." << endl();
27 Console.Out() << " Default minimum stack size is 64 kilobytes." << endl();
28 Console.Out() << "--max-stack-size=MAXSTACKSIZE (-s=MAXSTACKSIZE)" << endl();
29 Console.Out() << " Set maximum size stack size to MAXSTACKSIZE bytes." << endl();
30 Console.Out() << " Default maximum stack size is 4 megabytes." << endl();
31 Console.Out() << "--stack-size-increment=INCREMENT (-i=INCREMENT)" << endl();
32 Console.Out() << " Set stack size increment to INCREMENT bytes." << endl();
33 Console.Out() << " Default stack size increment is 64 kilobytes." << endl();
34 Console.Out() << "--debug (-d)" << endl();
35 Console.Out() << " Debug linking." << endl();
36 }
37
38 int main(int argc, const char** argv)
39 {
40 try
41 {
42 string cmajorRootDir = RtGetEnvironmentVariable("CMAJOR_ROOT");
43 if (cmajorRootDir.IsEmpty())
44 {
45 throw Exception("please set CMAJOR_ROOT environment variable to /path/to/cmajor directory");
46 }
47 string mainPath = Path.Combine(cmajorRootDir, "projects/cmsx/build/main/lib/Main.o");
48 List<string> fileNames;
49 fileNames.Add(GetFullPath(mainPath));
50 bool verbose = false;
51 bool debug = false;
52 ulong minStackSize = 64u * cast<ulong>(1024u);
53 ulong maxStackSize = 4u * cast<ulong>(1024u) * cast<ulong>(1024u);
54 ulong stackSizeIncrement = 64u * cast<ulong>(1024u);
55 ulong initialPoolSize = 4u * cast<ulong>(1024u);
56 string executableFileName = GetFullPath("a.out");
57 string clsIdFileName;
58 bool userFilesGiven = false;
59 bool removeUnusedCode = true;
60 for (int i = 1; i < argc; ++i;)
61 {
62 string arg = argv[i];
63 if (arg.StartsWith("--"))
64 {
65 if (arg == "--help")
66 {
67 PrintHelp();
68 return 1;
69 }
70 else if (arg == "--verbose")
71 {
72 verbose = true;
73 }
74 else if (arg == "--debug")
75 {
76 debug = true;
77 }
78 else if (arg.StartsWith("--out="))
79 {
80 executableFileName = GetFullPath(arg.Substring(6));;
81 }
82 else if (arg.StartsWith("--clsid="))
83 {
84 clsIdFileName = GetFullPath(arg.Substring(8));
85 }
86 else if (arg.StartsWith("--min-stack-size="))
87 {
88 minStackSize = ParseULong(arg.Substring(17));
89 }
90 else if (arg.StartsWith("--max-stack-size="))
91 {
92 maxStackSize = ParseULong(arg.Substring(17));
93 }
94 else if (arg.StartsWith("--stack-size-increment="))
95 {
96 stackSizeIncrement = ParseULong(arg.Substring(23));
97 }
98 else
99 {
100 throw Exception("unknown option '" + arg + "'");
101 }
102 }
103 else if (arg.StartsWith("-"))
104 {
105 if (arg.StartsWith("-o="))
106 {
107 executableFileName = GetFullPath(arg.Substring(3));
108 }
109 else if (arg.StartsWith("-c="))
110 {
111 clsIdFileName = GetFullPath(arg.Substring(3));
112 }
113 else if (arg.StartsWith("-m="))
114 {
115 minStackSize = ParseULong(arg.Substring(3));
116 }
117 else if (arg.StartsWith("-s="))
118 {
119 maxStackSize = ParseULong(arg.Substring(3));
120 }
121 else if (arg.StartsWith("-i="))
122 {
123 stackSizeIncrement = ParseULong(arg.Substring(3));
124 }
125 else
126 {
127 string options = arg.Substring(1);
128 if (options.IsEmpty())
129 {
130 throw Exception("unknown option '" + arg + "'");
131 }
132 else
133 {
134 for (char o : options)
135 {
136 if (o == 'h')
137 {
138 PrintHelp();
139 return 1;
140 }
141 else if (o == 'v')
142 {
143 verbose = true;
144 }
145 else if (o == 'd')
146 {
147 debug = true;
148 }
149 else
150 {
151 throw Exception("unknown option '-" + string(o) + "'");
152 }
153 }
154 }
155 }
156 }
157 else
158 {
159 fileNames.Add(GetFullPath(arg));
160 userFilesGiven = true;
161 }
162 }
163 if (executableFileName.IsEmpty())
164 {
165 PrintHelp();
166 throw Exception("output executable file name missing");
167 }
168 if (!userFilesGiven)
169 {
170 PrintHelp();
171 throw Exception("no object or library files given");
172 }
173 if (verbose)
174 {
175 Console.Out() << "Cmajor System X Linker version " << Version() << endl();
176 }
177 ClassIdMap classIdMap;
178 if (!clsIdFileName.IsEmpty())
179 {
180 classIdMap.Read(clsIdFileName);
181 }
182 List<UniquePtr<BinaryFile>> binaryFiles;
183 for (const string& fileName : fileNames)
184 {
185 if (verbose)
186 {
187 Console.Out() << "> " << fileName << endl();
188 }
189 UniquePtr<BinaryFile> binaryFile = ReadBinaryFile(fileName);
190 binaryFile->AddSymbolsToAddressMap();
191 binaryFiles.Add(Rvalue(binaryFile));
192 }
193 if (minStackSize > maxStackSize)
194 {
195 throw Exception("error: minimum stack size (" + ToString(minStackSize) + ") is greater than maximum stack size (" + ToString(maxStackSize) + ")");
196 }
197 if (stackSizeIncrement > maxStackSize - minStackSize)
198 {
199 throw Exception("error: stack size increment (" + ToString(stackSizeIncrement) + ") is greater than difference of maximum stack size (" + ToString(maxStackSize) +
200 ") and minimum stack size (" + ToString(minStackSize) + ")");
201 }
202 ExecutableFile executable(executableFileName, true, minStackSize, maxStackSize, stackSizeIncrement, initialPoolSize);
203 Link(executable, binaryFiles, classIdMap, removeUnusedCode, debug);
204 if (verbose)
205 {
206 Console.Out() << "==> " << executableFileName << endl();
207 }
208 }
209 catch (const Exception& ex)
210 {
211 Console.Error() << ex.Message() << endl();
212 return 1;
213 }
214 return 0;
215 }