1 |
786 |
skrzyp |
// ####ECOSHOSTGPLCOPYRIGHTBEGIN####
|
2 |
|
|
// -------------------------------------------
|
3 |
|
|
// This file is part of the eCos host tools.
|
4 |
|
|
// Copyright (C) 1998, 1999, 2000 Free Software Foundation, Inc.
|
5 |
|
|
//
|
6 |
|
|
// This program is free software; you can redistribute it and/or modify
|
7 |
|
|
// it under the terms of the GNU General Public License as published by
|
8 |
|
|
// the Free Software Foundation; either version 2 or (at your option) any
|
9 |
|
|
// later version.
|
10 |
|
|
//
|
11 |
|
|
// This program is distributed in the hope that it will be useful, but
|
12 |
|
|
// WITHOUT ANY WARRANTY; without even the implied warranty of
|
13 |
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
14 |
|
|
// General Public License for more details.
|
15 |
|
|
//
|
16 |
|
|
// You should have received a copy of the GNU General Public License
|
17 |
|
|
// along with this program; if not, write to the
|
18 |
|
|
// Free Software Foundation, Inc., 51 Franklin Street,
|
19 |
|
|
// Fifth Floor, Boston, MA 02110-1301, USA.
|
20 |
|
|
// -------------------------------------------
|
21 |
|
|
// ####ECOSHOSTGPLCOPYRIGHTEND####
|
22 |
|
|
//==========================================================================
|
23 |
|
|
//
|
24 |
|
|
// permtest.cxx
|
25 |
|
|
//
|
26 |
|
|
// Create a configuration based on a .ptest file
|
27 |
|
|
//
|
28 |
|
|
//==========================================================================
|
29 |
|
|
//==========================================================================
|
30 |
|
|
//#####DESCRIPTIONBEGIN####
|
31 |
|
|
//
|
32 |
|
|
// Author(s): bartv
|
33 |
|
|
// Contributors: bartv
|
34 |
|
|
// Date: 1999-11-05
|
35 |
|
|
//
|
36 |
|
|
//####DESCRIPTIONEND####
|
37 |
|
|
//==========================================================================
|
38 |
|
|
|
39 |
|
|
#include <cdl.hxx>
|
40 |
|
|
#include <cstdio>
|
41 |
|
|
#include <cstdlib>
|
42 |
|
|
|
43 |
|
|
// ----------------------------------------------------------------------------
|
44 |
|
|
// Statics.
|
45 |
|
|
//
|
46 |
|
|
// The global configuration is created as the result of a pkgconf command
|
47 |
|
|
// when executing the .ptest file
|
48 |
|
|
static CdlConfiguration configuration = 0;
|
49 |
|
|
|
50 |
|
|
// The database is set up before the script is evaluated.
|
51 |
|
|
static CdlPackagesDatabase database = 0;
|
52 |
|
|
|
53 |
|
|
// The component repository can come from a command line argument or from
|
54 |
|
|
// an environment variable.
|
55 |
|
|
static char* component_repository = 0;
|
56 |
|
|
|
57 |
|
|
// The name of the .ptest file. This is also the name used for the configuration.
|
58 |
|
|
static std::string ptest_file = "";
|
59 |
|
|
|
60 |
|
|
// The target comes from a command line argument, and is needed by
|
61 |
|
|
// tcl_pkgconf_command()
|
62 |
|
|
std::string target = "";
|
63 |
|
|
|
64 |
|
|
// The startup comes from a command line argument.
|
65 |
|
|
static char* startup = 0;
|
66 |
|
|
|
67 |
|
|
// ----------------------------------------------------------------------------
|
68 |
|
|
// Diagnostics support
|
69 |
|
|
static void error_fn(std::string msg)
|
70 |
|
|
{
|
71 |
|
|
fprintf(stderr, "%s\n", msg.c_str());
|
72 |
|
|
exit(EXIT_FAILURE);
|
73 |
|
|
}
|
74 |
|
|
|
75 |
|
|
static void warn_fn(std::string msg)
|
76 |
|
|
{
|
77 |
|
|
fprintf(stderr, "%s\n", msg.c_str());
|
78 |
|
|
}
|
79 |
|
|
|
80 |
|
|
// ----------------------------------------------------------------------------
|
81 |
|
|
// Given a database, output the known targets. This happens in response to
|
82 |
|
|
// the --targets flag or when the specified target is known.
|
83 |
|
|
// It is up to the calling code to exit with a suitable error code.
|
84 |
|
|
void
|
85 |
|
|
output_targets()
|
86 |
|
|
{
|
87 |
|
|
if (0 == database) {
|
88 |
|
|
fprintf(stderr, "Internal error, attempt to list targets when there is no database.\n");
|
89 |
|
|
exit(EXIT_FAILURE);
|
90 |
|
|
}
|
91 |
|
|
const std::vector<std::string>& known_targets = database->get_targets();
|
92 |
|
|
std::vector<std::string>::const_iterator target_i;
|
93 |
|
|
|
94 |
|
|
printf("Known targets:\n");
|
95 |
|
|
for (target_i = known_targets.begin(); target_i != known_targets.end(); target_i++) {
|
96 |
|
|
printf(" %s\n", target_i->c_str());
|
97 |
|
|
}
|
98 |
|
|
}
|
99 |
|
|
|
100 |
|
|
// ----------------------------------------------------------------------------
|
101 |
|
|
// Given a component repository and a permutation argument, find the
|
102 |
|
|
// corresponding .ptest file and store the result in the global ptest_file
|
103 |
|
|
static void find_ptest(CdlInterpreter interp, char* ptest_arg)
|
104 |
|
|
{
|
105 |
|
|
if (interp->is_file(ptest_arg)) {
|
106 |
|
|
ptest_file = ptest_arg;
|
107 |
|
|
return;
|
108 |
|
|
}
|
109 |
|
|
std::string tmp = std::string(ptest_arg) + ".ptest";
|
110 |
|
|
if (interp->is_file(tmp)) {
|
111 |
|
|
ptest_file = tmp;
|
112 |
|
|
return;
|
113 |
|
|
}
|
114 |
|
|
tmp = std::string(component_repository) + "/../testing/pkgtest/permtests/" + ptest_arg;
|
115 |
|
|
if (interp->is_file(tmp)) {
|
116 |
|
|
ptest_file = tmp;
|
117 |
|
|
return;
|
118 |
|
|
}
|
119 |
|
|
tmp += ".ptest";
|
120 |
|
|
if (interp->is_file(tmp)) {
|
121 |
|
|
ptest_file = tmp;
|
122 |
|
|
return;
|
123 |
|
|
}
|
124 |
|
|
}
|
125 |
|
|
|
126 |
|
|
// ----------------------------------------------------------------------------
|
127 |
|
|
// Given an alias for a target or package, turn it into the canonical name.
|
128 |
|
|
std::string
|
129 |
|
|
get_target_canonical_name(std::string alias)
|
130 |
|
|
{
|
131 |
|
|
if (0 == database) {
|
132 |
|
|
fprintf(stderr, "Internal error, attempt to get target canonical name when there is no database.\n");
|
133 |
|
|
exit(EXIT_FAILURE);
|
134 |
|
|
}
|
135 |
|
|
|
136 |
|
|
std::string result = "";
|
137 |
|
|
const std::vector<std::string>& known_targets = database->get_targets();
|
138 |
|
|
std::vector<std::string>::const_iterator target_i;
|
139 |
|
|
for (target_i = known_targets.begin(); ("" == result) && (target_i != known_targets.end()); target_i++) {
|
140 |
|
|
if (alias == *target_i) {
|
141 |
|
|
result = alias;
|
142 |
|
|
break;
|
143 |
|
|
}
|
144 |
|
|
|
145 |
|
|
const std::vector<std::string>& aliases = database->get_target_aliases(*target_i);
|
146 |
|
|
std::vector<std::string>::const_iterator alias_i;
|
147 |
|
|
for (alias_i = aliases.begin(); alias_i != aliases.end(); alias_i++) {
|
148 |
|
|
if (alias == *alias_i) {
|
149 |
|
|
result = *target_i;
|
150 |
|
|
break;
|
151 |
|
|
}
|
152 |
|
|
}
|
153 |
|
|
}
|
154 |
|
|
|
155 |
|
|
return result;
|
156 |
|
|
}
|
157 |
|
|
|
158 |
|
|
std::string
|
159 |
|
|
get_package_canonical_name(std::string alias)
|
160 |
|
|
{
|
161 |
|
|
if (0 == database) {
|
162 |
|
|
fprintf(stderr, "Internal error, attempt to get package canonical name when there is no database.\n");
|
163 |
|
|
exit(EXIT_FAILURE);
|
164 |
|
|
}
|
165 |
|
|
|
166 |
|
|
std::string result = "";
|
167 |
|
|
const std::vector<std::string>& known_packages = database->get_packages();
|
168 |
|
|
std::vector<std::string>::const_iterator package_i;
|
169 |
|
|
for (package_i = known_packages.begin(); ("" == result) && (package_i != known_packages.end()); package_i++) {
|
170 |
|
|
if (alias == *package_i) {
|
171 |
|
|
result = alias;
|
172 |
|
|
break;
|
173 |
|
|
}
|
174 |
|
|
|
175 |
|
|
const std::vector<std::string>& aliases = database->get_package_aliases(*package_i);
|
176 |
|
|
std::vector<std::string>::const_iterator alias_i;
|
177 |
|
|
for (alias_i = aliases.begin(); alias_i != aliases.end(); alias_i++) {
|
178 |
|
|
if (alias == *alias_i) {
|
179 |
|
|
result = *package_i;
|
180 |
|
|
break;
|
181 |
|
|
}
|
182 |
|
|
}
|
183 |
|
|
}
|
184 |
|
|
|
185 |
|
|
return result;
|
186 |
|
|
}
|
187 |
|
|
|
188 |
|
|
// ----------------------------------------------------------------------------
|
189 |
|
|
// The pkgconf command is responsible for creating the initial
|
190 |
|
|
// configuration. This should use the hardware as per the command-line
|
191 |
|
|
// target argument, either the default template or the uITRON package
|
192 |
|
|
// depending on the presence of an explicit -disable-uitron or
|
193 |
|
|
// --disable-uitron argument, and any additional packages added
|
194 |
|
|
// or removed.
|
195 |
|
|
|
196 |
|
|
static int
|
197 |
|
|
tcl_pkgconf_command(CdlInterpreter interp, int argc, char** argv)
|
198 |
|
|
{
|
199 |
|
|
if (0 != configuration) {
|
200 |
|
|
interp->set_result("Invalid `pkgconf' command, the configuration already exists.");
|
201 |
|
|
return TCL_ERROR;
|
202 |
|
|
}
|
203 |
|
|
if ("" == target) {
|
204 |
|
|
interp->set_result("Internal error, attempt to create a configuration with no known target.");
|
205 |
|
|
return TCL_ERROR;
|
206 |
|
|
}
|
207 |
|
|
if (0 == database) {
|
208 |
|
|
interp->set_result("Internal error, attempt to create a configuration before the database has been initialized.");
|
209 |
|
|
return TCL_ERROR;
|
210 |
|
|
}
|
211 |
|
|
if ("" == ptest_file) {
|
212 |
|
|
interp->set_result("Internal error, attempt to create a configuration when the .ptest file is unknown.");
|
213 |
|
|
return TCL_ERROR;
|
214 |
|
|
}
|
215 |
|
|
|
216 |
|
|
// Create a new interpreter for the configuration. Re-using the one
|
217 |
|
|
// being used for evaluating the .ptest file could cause problems.
|
218 |
|
|
CdlInterpreter new_interp = CdlInterpreterBody::make();
|
219 |
|
|
if (0 == new_interp) {
|
220 |
|
|
interp->set_result("Unable to create a new Tcl interpreter, out of memory?");
|
221 |
|
|
return TCL_ERROR;
|
222 |
|
|
}
|
223 |
|
|
|
224 |
|
|
configuration = CdlConfigurationBody::make(ptest_file, database, new_interp);
|
225 |
|
|
if (0 == configuration) {
|
226 |
|
|
interp->set_result("Unable to create a new configuration, out of memory?");
|
227 |
|
|
return TCL_ERROR;
|
228 |
|
|
}
|
229 |
|
|
|
230 |
|
|
bool uitron = true;
|
231 |
|
|
int i;
|
232 |
|
|
for (i = 1; i < argc; i++) {
|
233 |
|
|
if ((0 == strcmp(argv[i], "-disable-uitron")) || (0 == strcmp(argv[i], "--disable-uitron"))) {
|
234 |
|
|
uitron = false;
|
235 |
|
|
break;
|
236 |
|
|
}
|
237 |
|
|
}
|
238 |
|
|
|
239 |
|
|
try {
|
240 |
|
|
configuration->set_hardware(target, &error_fn, &warn_fn);
|
241 |
|
|
if (uitron) {
|
242 |
|
|
configuration->set_template("uitron", "", &error_fn, &warn_fn);
|
243 |
|
|
} else {
|
244 |
|
|
configuration->set_template("default", "", &error_fn, &warn_fn);
|
245 |
|
|
}
|
246 |
|
|
|
247 |
|
|
for (i = 1; i < argc; i++) {
|
248 |
|
|
char* disable = 0;
|
249 |
|
|
char* enable = 0;
|
250 |
|
|
|
251 |
|
|
if (0 == strncmp(argv[i], "-disable-", 9)) {
|
252 |
|
|
disable = &(argv[i][9]);
|
253 |
|
|
} else if (0 == strncmp(argv[i], "--disable-", 10)) {
|
254 |
|
|
disable = &(argv[i][10]);
|
255 |
|
|
} else if (0 == strncmp(argv[i], "-enable-", 8)) {
|
256 |
|
|
enable = &(argv[i][8]);
|
257 |
|
|
} else if (0 == strncmp(argv[i], "--enable-", 9)) {
|
258 |
|
|
enable = &(argv[i][9]);
|
259 |
|
|
} else {
|
260 |
|
|
interp->set_result(std::string("Invalid pkgconf argument `") + argv[i] + "'");
|
261 |
|
|
return TCL_ERROR;
|
262 |
|
|
}
|
263 |
|
|
|
264 |
|
|
if ((0 != disable) && (0 != strcmp(disable, "uitron"))) {
|
265 |
|
|
std::string package = get_package_canonical_name(disable);
|
266 |
|
|
if ("" == package) {
|
267 |
|
|
interp->set_result(std::string("Error in pkgconf command, attempt to disable unknown package `") +
|
268 |
|
|
disable + "'");
|
269 |
|
|
return TCL_ERROR;
|
270 |
|
|
}
|
271 |
|
|
const std::vector<CdlLoadable>& loadables = configuration->get_loadables();
|
272 |
|
|
std::vector<CdlLoadable>::const_iterator package_i;
|
273 |
|
|
for (package_i = loadables.begin(); package_i != loadables.end(); package_i++) {
|
274 |
|
|
if (package == (*package_i)->get_name()) {
|
275 |
|
|
break;
|
276 |
|
|
}
|
277 |
|
|
}
|
278 |
|
|
if (package_i == loadables.end()) {
|
279 |
|
|
printf("Warning, pkgconf command, cannot disable %s because it is not loaded in the current configuration",
|
280 |
|
|
disable);
|
281 |
|
|
} else {
|
282 |
|
|
configuration->unload_package(package, false);
|
283 |
|
|
}
|
284 |
|
|
}
|
285 |
|
|
|
286 |
|
|
if (0 != enable) {
|
287 |
|
|
std::string package = get_package_canonical_name(enable);
|
288 |
|
|
if ("" == package) {
|
289 |
|
|
interp->set_result(std::string("Error in pkgconf command, attempt to enable unknown package `") +
|
290 |
|
|
enable + "'");
|
291 |
|
|
return TCL_ERROR;
|
292 |
|
|
}
|
293 |
|
|
const std::vector<CdlLoadable>& loadables = configuration->get_loadables();
|
294 |
|
|
std::vector<CdlLoadable>::const_iterator package_i;
|
295 |
|
|
for (package_i = loadables.begin(); package_i != loadables.end(); package_i++) {
|
296 |
|
|
if (package == (*package_i)->get_name()) {
|
297 |
|
|
break;
|
298 |
|
|
}
|
299 |
|
|
}
|
300 |
|
|
if (package_i != loadables.end()) {
|
301 |
|
|
interp->set_result(std::string("Error in pkgconf command, cannot enable `") + enable +
|
302 |
|
|
"' because it is already loaded in the current configuration.");
|
303 |
|
|
return TCL_ERROR;
|
304 |
|
|
}
|
305 |
|
|
configuration->load_package(package, "", &error_fn, &warn_fn, false);
|
306 |
|
|
}
|
307 |
|
|
}
|
308 |
|
|
} catch(std::bad_alloc) {
|
309 |
|
|
interp->set_result(std::string("Unexpected error, out of memory?"));
|
310 |
|
|
return TCL_ERROR;
|
311 |
|
|
} catch(CdlInputOutputException e) {
|
312 |
|
|
interp->set_result(std::string("File I/O exception: ") + e.get_message());
|
313 |
|
|
return TCL_ERROR;
|
314 |
|
|
} catch(CdlParseException e) {
|
315 |
|
|
interp->set_result(std::string("Parse error: ") + e.get_message());
|
316 |
|
|
return TCL_ERROR;
|
317 |
|
|
} catch(...) {
|
318 |
|
|
interp->set_result("Internal error, an unexpected C++ exception was raised");
|
319 |
|
|
return TCL_ERROR;
|
320 |
|
|
}
|
321 |
|
|
|
322 |
|
|
return TCL_OK;
|
323 |
|
|
}
|
324 |
|
|
|
325 |
|
|
// ----------------------------------------------------------------------------
|
326 |
|
|
// Other Tcl commands, on the whole these are straightforward.
|
327 |
|
|
static int
|
328 |
|
|
tcl_header_command(CdlInterpreter interp, int argc, char** argv)
|
329 |
|
|
{
|
330 |
|
|
// Modifying a configuration no longer involves editing
|
331 |
|
|
// a header file. Instead a single overall configuration
|
332 |
|
|
// is updated, and then a savefile is generated. All that
|
333 |
|
|
// is necessary is to evaluate the second argument, which
|
334 |
|
|
// should be a Tcl script containing enable/disable/value
|
335 |
|
|
// commands.
|
336 |
|
|
if (3 != argc) {
|
337 |
|
|
interp->set_result("Invalid `header' command, expecting two arguments.");
|
338 |
|
|
return TCL_ERROR;
|
339 |
|
|
}
|
340 |
|
|
if (0 == configuration) {
|
341 |
|
|
interp->set_result("`header' command detected before the configuration was created.");
|
342 |
|
|
return TCL_ERROR;
|
343 |
|
|
}
|
344 |
|
|
std::string str_result;
|
345 |
|
|
int result = interp->eval(argv[2], str_result);
|
346 |
|
|
return result;
|
347 |
|
|
}
|
348 |
|
|
|
349 |
|
|
static int
|
350 |
|
|
tcl_makefile_command(CdlInterpreter interp, int argc, char** argv)
|
351 |
|
|
{
|
352 |
|
|
// The makefile command was used to modify the compiler flags.
|
353 |
|
|
// This happens very differently in the CDL world, and the
|
354 |
|
|
// best solution for now is to ignore this command completely.
|
355 |
|
|
if (3 != argc) {
|
356 |
|
|
interp->set_result("Invalid `makefile' command, expecting two arguments.");
|
357 |
|
|
return TCL_ERROR;
|
358 |
|
|
}
|
359 |
|
|
if (0 == configuration) {
|
360 |
|
|
interp->set_result("`header' command detected before the configuration was created.");
|
361 |
|
|
return TCL_ERROR;
|
362 |
|
|
}
|
363 |
|
|
return TCL_OK;
|
364 |
|
|
}
|
365 |
|
|
|
366 |
|
|
static int
|
367 |
|
|
tcl_enable_command(CdlInterpreter interp, int argc, char** argv)
|
368 |
|
|
{
|
369 |
|
|
// There should be one argument, the name of a configuration option.
|
370 |
|
|
if (2 != argc) {
|
371 |
|
|
interp->set_result("Invalid `enable' command, expecting one argument.");
|
372 |
|
|
return TCL_ERROR;
|
373 |
|
|
}
|
374 |
|
|
if (0 == configuration) {
|
375 |
|
|
interp->set_result("`enable' command detected before the configuration was created.");
|
376 |
|
|
return TCL_ERROR;
|
377 |
|
|
}
|
378 |
|
|
|
379 |
|
|
CdlNode node = configuration->lookup(argv[1]);
|
380 |
|
|
if (0 == node) {
|
381 |
|
|
printf("Warning, attempt to enable unknown option %s\n", argv[1]);
|
382 |
|
|
return TCL_OK;
|
383 |
|
|
}
|
384 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(node);
|
385 |
|
|
if ((0 == valuable) || !valuable->is_modifiable()) {
|
386 |
|
|
printf("Warning, attempt to disable non-modifiable option %s\n", argv[1]);
|
387 |
|
|
return TCL_OK;
|
388 |
|
|
}
|
389 |
|
|
CdlValueFlavor flavor = valuable->get_flavor();
|
390 |
|
|
if ((CdlValueFlavor_Bool != flavor) && (CdlValueFlavor_BoolData != flavor)) {
|
391 |
|
|
printf("Warning, attempt to disable non-boolean option %s\n", argv[1]);
|
392 |
|
|
return TCL_OK;
|
393 |
|
|
}
|
394 |
|
|
|
395 |
|
|
valuable->enable(CdlValueSource_User);
|
396 |
|
|
return TCL_OK;
|
397 |
|
|
}
|
398 |
|
|
|
399 |
|
|
static int
|
400 |
|
|
tcl_disable_command(CdlInterpreter interp, int argc, char** argv)
|
401 |
|
|
{
|
402 |
|
|
// There should be one argument, the name of a configuration option.
|
403 |
|
|
if (2 != argc) {
|
404 |
|
|
interp->set_result("Invalid `disable' command, expecting one argument.");
|
405 |
|
|
return TCL_ERROR;
|
406 |
|
|
}
|
407 |
|
|
if (0 == configuration) {
|
408 |
|
|
interp->set_result("`header' command detected before the configuration was created.");
|
409 |
|
|
return TCL_ERROR;
|
410 |
|
|
}
|
411 |
|
|
|
412 |
|
|
CdlNode node = configuration->lookup(argv[1]);
|
413 |
|
|
if (0 == node) {
|
414 |
|
|
printf("Warning, attempt to disable unknown option %s\n", argv[1]);
|
415 |
|
|
return TCL_OK;
|
416 |
|
|
}
|
417 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(node);
|
418 |
|
|
if ((0 == valuable) || !valuable->is_modifiable()) {
|
419 |
|
|
printf("Warning, attempt to disable non-modifiable option %s\n", argv[1]);
|
420 |
|
|
return TCL_OK;
|
421 |
|
|
}
|
422 |
|
|
CdlValueFlavor flavor = valuable->get_flavor();
|
423 |
|
|
if ((CdlValueFlavor_Bool != flavor) && (CdlValueFlavor_BoolData != flavor)) {
|
424 |
|
|
printf("Warning, attempt to disable non-boolean option %s\n", argv[1]);
|
425 |
|
|
return TCL_OK;
|
426 |
|
|
}
|
427 |
|
|
|
428 |
|
|
valuable->disable(CdlValueSource_User);
|
429 |
|
|
return TCL_OK;
|
430 |
|
|
}
|
431 |
|
|
|
432 |
|
|
static int
|
433 |
|
|
tcl_value_command(CdlInterpreter interp, int argc, char** argv)
|
434 |
|
|
{
|
435 |
|
|
// There should be two argument, the name of a configuration option and the new value
|
436 |
|
|
if (3 != argc) {
|
437 |
|
|
interp->set_result("Invalid `value' command, expecting two arguments.");
|
438 |
|
|
return TCL_ERROR;
|
439 |
|
|
}
|
440 |
|
|
if (0 == configuration) {
|
441 |
|
|
interp->set_result("`value' command detected before the configuration was created.");
|
442 |
|
|
return TCL_ERROR;
|
443 |
|
|
}
|
444 |
|
|
|
445 |
|
|
CdlNode node = configuration->lookup(argv[1]);
|
446 |
|
|
if (0 == node) {
|
447 |
|
|
printf("Warning, attempt to change the value of an unknown option %s\n", argv[1]);
|
448 |
|
|
return TCL_OK;
|
449 |
|
|
}
|
450 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(node);
|
451 |
|
|
if ((0 == valuable) || !valuable->is_modifiable()) {
|
452 |
|
|
printf("Warning, attempt to change the value of non-modifiable option %s\n", argv[1]);
|
453 |
|
|
return TCL_OK;
|
454 |
|
|
}
|
455 |
|
|
CdlValueFlavor flavor = valuable->get_flavor();
|
456 |
|
|
if ((CdlValueFlavor_BoolData != flavor) && (CdlValueFlavor_Data != flavor)) {
|
457 |
|
|
printf("Warning, attempt to change the value of non-data option %s\n", argv[1]);
|
458 |
|
|
return TCL_OK;
|
459 |
|
|
}
|
460 |
|
|
|
461 |
|
|
valuable->set_value(argv[2], CdlValueSource_User);
|
462 |
|
|
|
463 |
|
|
// There's no point setting the value for a BoolData but keeping it disabled
|
464 |
|
|
if (CdlValueFlavor_BoolData == flavor) {
|
465 |
|
|
valuable->enable(CdlValueSource_User);
|
466 |
|
|
}
|
467 |
|
|
|
468 |
|
|
return TCL_OK;
|
469 |
|
|
}
|
470 |
|
|
|
471 |
|
|
// ----------------------------------------------------------------------------
|
472 |
|
|
// Specifying the startup. There should be an option CYGHWR_HAL_STARTUP
|
473 |
|
|
// or CYG_HAL_STARTUP which can be set to the appropriate value.
|
474 |
|
|
static void
|
475 |
|
|
process_startup()
|
476 |
|
|
{
|
477 |
|
|
if (0 == configuration) {
|
478 |
|
|
fprintf(stderr, "Error: attempting to set the startup before a configuration has been created.\n");
|
479 |
|
|
exit(EXIT_FAILURE);
|
480 |
|
|
}
|
481 |
|
|
if (0 == startup) {
|
482 |
|
|
fprintf(stderr, "Error: no startup has been specified.\n");
|
483 |
|
|
exit(EXIT_FAILURE);
|
484 |
|
|
}
|
485 |
|
|
|
486 |
|
|
CdlNode node = configuration->lookup("CYGHWR_HAL_STARTUP");
|
487 |
|
|
if (0 == node) {
|
488 |
|
|
node = configuration->lookup("CYG_HAL_STARTUP");
|
489 |
|
|
}
|
490 |
|
|
if (0 == node) {
|
491 |
|
|
printf("Warning, there is no option CYGHWR_HAL_STARTUP in the current configuration.\n");
|
492 |
|
|
return;
|
493 |
|
|
}
|
494 |
|
|
CdlValuable valuable = dynamic_cast<CdlValuable>(node);
|
495 |
|
|
if (0 == valuable) {
|
496 |
|
|
fprintf(stderr, "Error: CYGHWR_HAL_STARTUP exists but is not an option in the current configuration.\n");
|
497 |
|
|
exit(EXIT_FAILURE);
|
498 |
|
|
}
|
499 |
|
|
valuable->set_value(startup, CdlValueSource_User);
|
500 |
|
|
}
|
501 |
|
|
|
502 |
|
|
// ----------------------------------------------------------------------------
|
503 |
|
|
static void
|
504 |
|
|
usage(void)
|
505 |
|
|
{
|
506 |
|
|
printf("Usage: permtest [options] -target <target> -startup <startup> <ptest>\n");
|
507 |
|
|
printf(" permtest --help\n");
|
508 |
|
|
printf(" permtest --targets\n");
|
509 |
|
|
printf("\n");
|
510 |
|
|
printf(" Valid options are:\n");
|
511 |
|
|
printf(" -srcdir <component repository>\n");
|
512 |
|
|
|
513 |
|
|
// It is up to the calling code to exit with a suitable exit code.
|
514 |
|
|
}
|
515 |
|
|
|
516 |
|
|
// ----------------------------------------------------------------------------
|
517 |
|
|
int
|
518 |
|
|
main(int argc, char** argv)
|
519 |
|
|
{
|
520 |
|
|
bool list_targets = false;
|
521 |
|
|
bool show_help = false;
|
522 |
|
|
char* target_arg = 0;
|
523 |
|
|
char* ptest_arg = 0;
|
524 |
|
|
|
525 |
|
|
// Time to process all the arguments.
|
526 |
|
|
int i;
|
527 |
|
|
for (i = 1; i < argc; i++) {
|
528 |
|
|
|
529 |
|
|
// If there are any -- arguments, ignore the first -
|
530 |
|
|
char* arg = argv[i];
|
531 |
|
|
if (('-' == arg[0]) && ('-' == arg[1])) {
|
532 |
|
|
arg = &(arg[1]);
|
533 |
|
|
}
|
534 |
|
|
|
535 |
|
|
if ((0 == strcmp("-help", arg)) || (0 == strcmp("-H", arg))) {
|
536 |
|
|
show_help = true;
|
537 |
|
|
continue;
|
538 |
|
|
}
|
539 |
|
|
|
540 |
|
|
if (0 == strcmp("-targets", arg)) {
|
541 |
|
|
list_targets = true;
|
542 |
|
|
continue;
|
543 |
|
|
}
|
544 |
|
|
|
545 |
|
|
if (0 == strncmp("-target", arg, 7)) {
|
546 |
|
|
if (0 != target_arg) {
|
547 |
|
|
fprintf(stderr, "Only one target should be specified.\n");
|
548 |
|
|
usage();
|
549 |
|
|
exit(EXIT_FAILURE);
|
550 |
|
|
}
|
551 |
|
|
if ('=' == arg[7]) {
|
552 |
|
|
target_arg = &(arg[8]);
|
553 |
|
|
} else {
|
554 |
|
|
if (++i == argc) {
|
555 |
|
|
fprintf(stderr, "Missing argument after -target\n");
|
556 |
|
|
usage();
|
557 |
|
|
exit(EXIT_FAILURE);
|
558 |
|
|
}
|
559 |
|
|
target_arg = argv[i];
|
560 |
|
|
}
|
561 |
|
|
continue;
|
562 |
|
|
}
|
563 |
|
|
if (0 == strncmp("-srcdir", arg, 7)) {
|
564 |
|
|
if (0 != component_repository) {
|
565 |
|
|
fprintf(stderr, "The component repository should be specified only once.\n");
|
566 |
|
|
usage();
|
567 |
|
|
exit(EXIT_FAILURE);
|
568 |
|
|
}
|
569 |
|
|
if ('=' == arg[7]) {
|
570 |
|
|
component_repository = &(arg[8]);
|
571 |
|
|
} else {
|
572 |
|
|
if (++i == argc) {
|
573 |
|
|
fprintf(stderr, "Missing argument after -srcdir\n");
|
574 |
|
|
usage();
|
575 |
|
|
exit(EXIT_FAILURE);
|
576 |
|
|
}
|
577 |
|
|
component_repository = argv[i];
|
578 |
|
|
}
|
579 |
|
|
continue;
|
580 |
|
|
}
|
581 |
|
|
if (0 == strncmp("-startup", argv[i], 8)) {
|
582 |
|
|
if (0 != startup) {
|
583 |
|
|
fprintf(stderr, "The startup mode should be specified only once.\n");
|
584 |
|
|
usage();
|
585 |
|
|
exit(EXIT_FAILURE);
|
586 |
|
|
}
|
587 |
|
|
if ('=' == arg[8]) {
|
588 |
|
|
startup = &(arg[9]);
|
589 |
|
|
} else {
|
590 |
|
|
if (++i == argc) {
|
591 |
|
|
fprintf(stderr, "Missing argument after -startup\n");
|
592 |
|
|
usage();
|
593 |
|
|
exit(EXIT_FAILURE);
|
594 |
|
|
}
|
595 |
|
|
startup = argv[i];
|
596 |
|
|
}
|
597 |
|
|
continue;
|
598 |
|
|
}
|
599 |
|
|
|
600 |
|
|
// None of the standard arguments, this had better be a ptest
|
601 |
|
|
if (0 == ptest_arg) {
|
602 |
|
|
ptest_arg = argv[i];
|
603 |
|
|
continue;
|
604 |
|
|
} else {
|
605 |
|
|
fprintf(stderr, "Invalid argument %s, only one permutation file should be specified.\n", argv[i]);
|
606 |
|
|
usage();
|
607 |
|
|
exit(EXIT_FAILURE);
|
608 |
|
|
}
|
609 |
|
|
}
|
610 |
|
|
|
611 |
|
|
// That takes care of the argument processing, time to do
|
612 |
|
|
// something interesting.
|
613 |
|
|
if (show_help) {
|
614 |
|
|
usage();
|
615 |
|
|
return EXIT_SUCCESS;
|
616 |
|
|
}
|
617 |
|
|
|
618 |
|
|
// Locate the component repository. This can come from either a
|
619 |
|
|
// command-line argument or from an environment variable. The
|
620 |
|
|
// component repository is validated by creating a database.
|
621 |
|
|
if ((0 == component_repository) || ('\0' == component_repository[0])) {
|
622 |
|
|
component_repository = getenv("ECOS_REPOSITORY");
|
623 |
|
|
if (0 == component_repository) {
|
624 |
|
|
fprintf(stderr, "The eCos repository location is unknown.\n");
|
625 |
|
|
fprintf(stderr, "Please use a --srcdir command line argument, or set\n");
|
626 |
|
|
fprintf(stderr, "the ECOS_REPOSITORY environment variable.\n");
|
627 |
|
|
exit(EXIT_FAILURE);
|
628 |
|
|
}
|
629 |
|
|
}
|
630 |
|
|
|
631 |
|
|
// Create the Tcl interpreter, to provide ready access to the file
|
632 |
|
|
// system and for processing the permutation file itself.
|
633 |
|
|
CdlInterpreter interp = CdlInterpreterBody::make();
|
634 |
|
|
if (0 == interp) {
|
635 |
|
|
fprintf(stderr, "Internal error, unable to create a Tcl interpreter.\n");
|
636 |
|
|
exit(EXIT_FAILURE);
|
637 |
|
|
}
|
638 |
|
|
interp->push_context("permtest");
|
639 |
|
|
interp->push_error_fn_ptr(&error_fn);
|
640 |
|
|
interp->push_warning_fn_ptr(&warn_fn);
|
641 |
|
|
|
642 |
|
|
// Now look for the ptest file.
|
643 |
|
|
if ((0 == ptest_arg) || ('\0' == ptest_arg[0])) {
|
644 |
|
|
fprintf(stderr, "Please specify a permutation to be tested, e.g. default.ptest\n");
|
645 |
|
|
usage();
|
646 |
|
|
exit(EXIT_FAILURE);
|
647 |
|
|
}
|
648 |
|
|
find_ptest(interp, ptest_arg);
|
649 |
|
|
if ("" == ptest_file) {
|
650 |
|
|
fprintf(stderr, "Unable to locate a permutation file corresponding to %s\n", ptest_arg);
|
651 |
|
|
exit(EXIT_FAILURE);
|
652 |
|
|
}
|
653 |
|
|
|
654 |
|
|
try {
|
655 |
|
|
database = CdlPackagesDatabaseBody::make(component_repository, &error_fn, &warn_fn);
|
656 |
|
|
} catch(std::bad_alloc) {
|
657 |
|
|
fprintf(stderr, "Failed to initialize the component repository database, out of memory?\n");
|
658 |
|
|
exit(EXIT_FAILURE);
|
659 |
|
|
} catch(CdlInputOutputException e) {
|
660 |
|
|
fprintf(stderr, "Failed to initialize the component repository database.\n");
|
661 |
|
|
fprintf(stderr, " %s\n", e.get_message().c_str());
|
662 |
|
|
exit(EXIT_FAILURE);
|
663 |
|
|
} catch(...) {
|
664 |
|
|
fprintf(stderr, "Internal error, unexpected C++ exception while initializing the component repository database.\n");
|
665 |
|
|
exit(EXIT_FAILURE);
|
666 |
|
|
}
|
667 |
|
|
|
668 |
|
|
// Once we have a database we can process the target.
|
669 |
|
|
if (list_targets) {
|
670 |
|
|
output_targets();
|
671 |
|
|
exit(EXIT_SUCCESS);
|
672 |
|
|
}
|
673 |
|
|
if ((0 == target_arg) || ('\0' == target_arg[0])) {
|
674 |
|
|
fprintf(stderr, "Please specify a target using e.g. --target=xyz\n");
|
675 |
|
|
usage();
|
676 |
|
|
exit(EXIT_FAILURE);
|
677 |
|
|
}
|
678 |
|
|
target = get_target_canonical_name(target_arg);
|
679 |
|
|
if ("" == target) {
|
680 |
|
|
fprintf(stderr, "Invalid target %s\n", target_arg);
|
681 |
|
|
output_targets();
|
682 |
|
|
exit(EXIT_FAILURE);
|
683 |
|
|
}
|
684 |
|
|
|
685 |
|
|
if ((0 == startup) || ('\0' == startup[0])) {
|
686 |
|
|
fprintf(stderr, "Please specify a startup for this target, e.g. rom or ram\n");
|
687 |
|
|
usage();
|
688 |
|
|
exit(EXIT_FAILURE);
|
689 |
|
|
}
|
690 |
|
|
|
691 |
|
|
interp->add_command("pkgconf", &tcl_pkgconf_command);
|
692 |
|
|
interp->add_command("header", &tcl_header_command);
|
693 |
|
|
interp->add_command("makefile", &tcl_makefile_command);
|
694 |
|
|
interp->add_command("enable", &tcl_enable_command);
|
695 |
|
|
interp->add_command("disable", &tcl_disable_command);
|
696 |
|
|
interp->add_command("value", &tcl_value_command);
|
697 |
|
|
|
698 |
|
|
std::string str_result;
|
699 |
|
|
int result = interp->eval_file(ptest_file, str_result);
|
700 |
|
|
if (TCL_OK != result) {
|
701 |
|
|
fprintf(stderr, "An error occurred while processing the permutation file.\n");
|
702 |
|
|
fprintf(stderr, "%s\n", str_result.c_str());
|
703 |
|
|
exit(EXIT_FAILURE);
|
704 |
|
|
}
|
705 |
|
|
|
706 |
|
|
// Take care of the startup argument as well.
|
707 |
|
|
process_startup();
|
708 |
|
|
|
709 |
|
|
// Perform global conflict resolution, in case some of the
|
710 |
|
|
// conflicts were caused by the order in which packages were
|
711 |
|
|
// loaded.
|
712 |
|
|
configuration->resolve_all_conflicts();
|
713 |
|
|
|
714 |
|
|
// We now have a configuration. Is it valid?
|
715 |
|
|
bool valid = true;
|
716 |
|
|
const std::list<CdlConflict>& all_conflicts = configuration->get_all_conflicts();
|
717 |
|
|
std::list<CdlConflict>::const_iterator conf_i;
|
718 |
|
|
for (conf_i = all_conflicts.begin(); conf_i != all_conflicts.end(); conf_i++) {
|
719 |
|
|
// HACK: ignore any conflicts inside interfaces.
|
720 |
|
|
CdlNode node = (*conf_i)->get_node();
|
721 |
|
|
CdlInterface interface = dynamic_cast<CdlInterface>(node);
|
722 |
|
|
if (0 != interface) {
|
723 |
|
|
continue;
|
724 |
|
|
}
|
725 |
|
|
CdlProperty prop = (*conf_i)->get_property();
|
726 |
|
|
fprintf(stderr, "Conflict: %s %s, property %s\n %s\n", node->get_class_name().c_str(), node->get_name().c_str(),
|
727 |
|
|
prop->get_property_name().c_str(), (*conf_i)->get_explanation().c_str());
|
728 |
|
|
valid = false;
|
729 |
|
|
}
|
730 |
|
|
if (!valid) {
|
731 |
|
|
printf("This configuration is invalid and cannot be built.\n");
|
732 |
|
|
exit(EXIT_FAILURE);
|
733 |
|
|
}
|
734 |
|
|
|
735 |
|
|
// It appears we have a valid configuration. Generate the savefile.
|
736 |
|
|
try {
|
737 |
|
|
configuration->save("ecos.ecc");
|
738 |
|
|
} catch(std::bad_alloc) {
|
739 |
|
|
fprintf(stderr, "Unexpected error while saving configuration, out of memory?\n");
|
740 |
|
|
exit(EXIT_FAILURE);
|
741 |
|
|
} catch(CdlInputOutputException e) {
|
742 |
|
|
fprintf(stderr, "I/O error while saving configuration.\n");
|
743 |
|
|
fprintf(stderr, "%s\n", e.get_message().c_str());
|
744 |
|
|
exit(EXIT_FAILURE);
|
745 |
|
|
}
|
746 |
|
|
|
747 |
|
|
// Time to invoke ecosconfig. This needs a component repository environment variable
|
748 |
|
|
interp->set_variable("env(ECOS_REPOSITORY)", component_repository);
|
749 |
|
|
result = interp->eval("exec ecosconfig tree", str_result);
|
750 |
|
|
if (TCL_OK != result) {
|
751 |
|
|
fprintf(stderr, "Error when invoking ecosconfig\n");
|
752 |
|
|
fprintf(stderr, "%s\n", str_result.c_str());
|
753 |
|
|
exit(EXIT_FAILURE);
|
754 |
|
|
}
|
755 |
|
|
|
756 |
|
|
return EXIT_SUCCESS;
|
757 |
|
|
}
|