ENH: change the search path order (if several Tcl/Tk are installed, the "current...
[cmake.git] / Source / cmake.cxx
blob8f62bfcf5f928b627cdf5811cec90a6c214a411e
1 /*=========================================================================
3 Program: Insight Segmentation & Registration Toolkit
4 Module: $RCSfile: cmake.cxx,v $
5 Language: C++
6 Date: $Date: 2002-07-17 15:53:07 $
7 Version: $Revision: 1.70 $
9 Copyright (c) 2002 Insight Consortium. All rights reserved.
10 See ITKCopyright.txt or http://www.itk.org/HTML/Copyright.htm for details.
12 This software is distributed WITHOUT ANY WARRANTY; without even
13 the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
14 PURPOSE. See the above copyright notices for more information.
16 =========================================================================*/
17 #include "cmake.h"
18 #include "time.h"
19 #include "cmCacheManager.h"
21 // include the generator
22 #if defined(_WIN32) && !defined(__CYGWIN__)
23 #include "cmMSProjectGenerator.h"
24 #include "cmMSDotNETGenerator.h"
25 #include "cmBorlandMakefileGenerator.h"
26 #include "cmNMakeMakefileGenerator.h"
27 #else
28 #include "cmUnixMakefileGenerator.h"
29 #endif
31 cmake::cmake()
33 m_Verbose = false;
34 #if defined(_WIN32) && !defined(__CYGWIN__)
35 cmMakefileGenerator::RegisterGenerator(new cmMSProjectGenerator);
36 cmMakefileGenerator::RegisterGenerator(new cmMSDotNETGenerator);
37 cmMakefileGenerator::RegisterGenerator(new cmNMakeMakefileGenerator);
38 cmMakefileGenerator::RegisterGenerator(new cmBorlandMakefileGenerator);
39 #else
40 cmMakefileGenerator::RegisterGenerator(new cmUnixMakefileGenerator);
41 #endif
44 void cmake::Usage(const char* program)
46 cmStringStream errorStream;
48 errorStream << "cmake version " << cmMakefile::GetMajorVersion()
49 << "." << cmMakefile::GetMinorVersion() << "\n";
50 errorStream << "Usage: " << program << " [srcdir] [options]\n"
51 << "Where cmake is run from the directory where you want the object files written. If srcdir is not specified, the current directory is used for both source and object files.\n";
52 errorStream << "Options are:\n";
53 errorStream << "\n-i (puts cmake in wizard mode, not available for ccmake)\n";
54 errorStream << "\n-DVAR:TYPE=VALUE (create a cache file entry)\n";
55 errorStream << "\n-Cpath_to_initial_cache (a cmake list file that is used to pre-load the cache with values.)\n";
56 errorStream << "\n[-GgeneratorName] (where generator name can be one of these: ";
57 std::vector<std::string> names;
58 cmMakefileGenerator::GetRegisteredGenerators(names);
59 for(std::vector<std::string>::iterator i =names.begin();
60 i != names.end(); ++i)
62 errorStream << "\"" << i->c_str() << "\" ";
64 errorStream << ")\n";
66 cmSystemTools::Error(errorStream.str().c_str());
69 // Parse the args
70 void cmake::SetCacheArgs(cmMakefile& builder,
71 const std::vector<std::string>& args)
73 for(unsigned int i=1; i < args.size(); ++i)
75 std::string arg = args[i];
76 if(arg.find("-D",0) == 0)
78 std::string entry = arg.substr(2);
79 std::string var, value;
80 cmCacheManager::CacheEntryType type;
81 if(cmCacheManager::ParseEntry(entry.c_str(), var, value, type))
83 cmCacheManager::GetInstance()->AddCacheEntry(
84 var.c_str(),
85 value.c_str(),
86 "No help, variable specified on the command line.",
87 type);
89 else
91 std::cerr << "Parse error in command line argument: " << arg << "\n"
92 << "Should be: VAR:type=value\n";
95 else if(arg.find("-C",0) == 0)
97 std::string path = arg.substr(2);
98 std::cerr << "loading initial cache file " << path.c_str() << "\n";
99 if(!builder.ReadListFile(path.c_str()))
101 std::cerr << "Error in reading cmake initial cache file:"
102 << path.c_str() << "\n";
108 // Parse the args
109 void cmake::SetArgs(cmMakefile& builder, const std::vector<std::string>& args)
111 m_Local = false;
112 bool directoriesSet = false;
113 // watch for cmake and cmake srcdir invocations
114 if (args.size() <= 2)
116 directoriesSet = true;
117 builder.SetHomeOutputDirectory
118 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
119 builder.SetStartOutputDirectory
120 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
121 if (args.size() == 2)
123 builder.SetHomeDirectory
124 (cmSystemTools::CollapseFullPath(args[1].c_str()).c_str());
125 builder.SetStartDirectory
126 (cmSystemTools::CollapseFullPath(args[1].c_str()).c_str());
128 else
130 builder.SetHomeDirectory
131 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
132 builder.SetStartDirectory
133 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
137 for(unsigned int i=1; i < args.size(); ++i)
139 std::string arg = args[i];
140 if(arg.find("-H",0) == 0)
142 directoriesSet = true;
143 std::string path = arg.substr(2);
144 builder.SetHomeDirectory(path.c_str());
146 else if(arg.find("-S",0) == 0)
148 directoriesSet = true;
149 m_Local = true;
150 std::string path = arg.substr(2);
151 builder.SetStartDirectory(path.c_str());
153 else if(arg.find("-O",0) == 0)
155 directoriesSet = true;
156 std::string path = arg.substr(2);
157 builder.SetStartOutputDirectory(path.c_str());
159 else if(arg.find("-B",0) == 0)
161 directoriesSet = true;
162 std::string path = arg.substr(2);
163 builder.SetHomeOutputDirectory(path.c_str());
165 else if(arg.find("-V",0) == 0)
167 m_Verbose = true;
169 else if(arg.find("-D",0) == 0)
171 // skip for now
173 else if(arg.find("-C",0) == 0)
175 // skip for now
177 else if(arg.find("-G",0) == 0)
179 std::string value = arg.substr(2);
180 cmMakefileGenerator* gen =
181 cmMakefileGenerator::CreateGenerator(value.c_str());
182 if(!gen)
184 cmSystemTools::Error("Could not create named generator ",
185 value.c_str());
187 else
189 builder.SetMakefileGenerator(gen);
192 // no option assume it is the path to the source
193 else
195 directoriesSet = true;
196 builder.SetHomeOutputDirectory
197 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
198 builder.SetStartOutputDirectory
199 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
200 builder.SetHomeDirectory
201 (cmSystemTools::CollapseFullPath(arg.c_str()).c_str());
202 builder.SetStartDirectory
203 (cmSystemTools::CollapseFullPath(arg.c_str()).c_str());
206 if(!directoriesSet)
208 builder.SetHomeOutputDirectory
209 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
210 builder.SetStartOutputDirectory
211 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
212 builder.SetHomeDirectory
213 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
214 builder.SetStartDirectory
215 (cmSystemTools::GetCurrentWorkingDirectory().c_str());
217 if (!m_Local)
219 builder.SetStartDirectory(builder.GetHomeDirectory());
220 builder.SetStartOutputDirectory(builder.GetHomeOutputDirectory());
224 // at the end of this CMAKE_ROOT and CMAKE_COMMAND should be added to the cache
225 int cmake::AddCMakePaths(const std::vector<std::string>& args)
227 // Find our own executable.
228 std::vector<cmStdString> failures;
229 std::string cMakeSelf = args[0];
230 cmSystemTools::ConvertToUnixSlashes(cMakeSelf);
231 failures.push_back(cMakeSelf);
232 cMakeSelf = cmSystemTools::FindProgram(cMakeSelf.c_str());
233 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
235 #ifdef CMAKE_BUILD_DIR
236 std::string intdir = ".";
237 #ifdef CMAKE_INTDIR
238 intdir = CMAKE_INTDIR;
239 #endif
240 cMakeSelf = CMAKE_BUILD_DIR;
241 cMakeSelf += "/Source/";
242 cMakeSelf += intdir;
243 cMakeSelf += "/cmake";
244 cMakeSelf += cmSystemTools::GetExecutableExtension();
245 #endif
247 #ifdef CMAKE_PREFIX
248 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
250 failures.push_back(cMakeSelf);
251 cMakeSelf = CMAKE_PREFIX "/bin/cmake";
253 #endif
254 if(!cmSystemTools::FileExists(cMakeSelf.c_str()))
256 failures.push_back(cMakeSelf);
257 cmStringStream msg;
258 msg << "CMAKE can not find the command line program cmake.\n";
259 msg << " argv[0] = \"" << args[0].c_str() << "\"\n";
260 msg << " Attempted paths:\n";
261 std::vector<cmStdString>::iterator i;
262 for(i=failures.begin(); i != failures.end(); ++i)
264 msg << " \"" << i->c_str() << "\"\n";
266 cmSystemTools::Error(msg.str().c_str());
267 return 0;
269 // Save the value in the cache
270 cmCacheManager::GetInstance()->AddCacheEntry
271 ("CMAKE_COMMAND",cMakeSelf.c_str(), "Path to CMake executable.",
272 cmCacheManager::INTERNAL);
274 // Find and save the command to edit the cache
275 std::string editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
276 "/ccmake" + cmSystemTools::GetFilenameExtension(cMakeSelf);
277 if( !cmSystemTools::FileExists(editCacheCommand.c_str()))
279 editCacheCommand = cmSystemTools::GetFilenamePath(cMakeSelf) +
280 "/CMakeSetup" + cmSystemTools::GetFilenameExtension(cMakeSelf);
282 if(cmSystemTools::FileExists(editCacheCommand.c_str()))
284 cmCacheManager::GetInstance()->AddCacheEntry
285 ("CMAKE_EDIT_COMMAND", editCacheCommand.c_str(),
286 "Path to cache edit program executable.", cmCacheManager::INTERNAL);
289 // do CMAKE_ROOT, look for the environment variable first
290 std::string cMakeRoot;
291 std::string modules;
292 if (getenv("CMAKE_ROOT"))
294 cMakeRoot = getenv("CMAKE_ROOT");
295 modules = cMakeRoot + "/Modules/FindVTK.cmake";
297 if(!cmSystemTools::FileExists(modules.c_str()))
299 // next try exe/..
300 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
301 std::string::size_type slashPos = cMakeRoot.rfind("/");
302 if(slashPos != std::string::npos)
304 cMakeRoot = cMakeRoot.substr(0, slashPos);
306 // is there no Modules direcory there?
307 modules = cMakeRoot + "/Modules/FindVTK.cmake";
310 if (!cmSystemTools::FileExists(modules.c_str()))
312 // try exe/../share/cmake
313 cMakeRoot += "/share/CMake";
314 modules = cMakeRoot + "/Modules/FindVTK.cmake";
316 #ifdef CMAKE_ROOT_DIR
317 if (!cmSystemTools::FileExists(modules.c_str()))
319 // try compiled in root directory
320 cMakeRoot = CMAKE_ROOT_DIR;
321 modules = cMakeRoot + "/Modules/FindVTK.cmake";
323 #endif
324 #ifdef CMAKE_PREFIX
325 if (!cmSystemTools::FileExists(modules.c_str()))
327 // try compiled in install prefix
328 cMakeRoot = CMAKE_PREFIX "/share/CMake";
329 modules = cMakeRoot + "/Modules/FindVTK.cmake";
331 #endif
332 if (!cmSystemTools::FileExists(modules.c_str()))
334 // try
335 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
336 cMakeRoot += "/share/CMake";
337 modules = cMakeRoot + "/Modules/FindVTK.cmake";
339 if(!cmSystemTools::FileExists(modules.c_str()))
341 // next try exe
342 cMakeRoot = cmSystemTools::GetProgramPath(cMakeSelf.c_str());
343 // is there no Modules direcory there?
344 modules = cMakeRoot + "/Modules/FindVTK.cmake";
346 if (!cmSystemTools::FileExists(modules.c_str()))
348 // couldn't find modules
349 cmSystemTools::Error("Could not find CMAKE_ROOT !!!\n",
350 "Modules directory not in directory:\n",
351 modules.c_str());
352 return 0;
354 cmCacheManager::GetInstance()->AddCacheEntry
355 ("CMAKE_ROOT", cMakeRoot.c_str(),
356 "Path to CMake installation.", cmCacheManager::INTERNAL);
357 return 1;
362 int cmake::Generate(const std::vector<std::string>& args, bool buildMakefiles)
364 if(args.size() == 1 && !cmSystemTools::FileExists("CMakeLists.txt"))
366 this->Usage(args[0].c_str());
367 return -1;
369 // look for obvious request for help
370 for(unsigned int i=1; i < args.size(); ++i)
372 std::string arg = args[i];
373 if(arg.find("-help",0) != std::string::npos ||
374 arg.find("--help",0) != std::string::npos ||
375 arg.find("/?",0) != std::string::npos ||
376 arg.find("-usage",0) != std::string::npos)
378 this->Usage(args[0].c_str());
379 return -1;
382 // Create a makefile
383 cmMakefile mf;
384 // extract the directory arguments, could create a Generator
385 this->SetArgs(mf, args);
386 // Read and parse the input makefile
387 mf.MakeStartDirectoriesCurrent();
388 cmCacheManager::GetInstance()->LoadCache(&mf);
389 if(mf.GetDefinition("CMAKE_HOME_DIRECTORY"))
391 std::string cacheStart = mf.GetDefinition("CMAKE_HOME_DIRECTORY");
392 cacheStart += "/CMakeLists.txt";
393 std::string currentStart = mf.GetHomeDirectory();
394 currentStart += "/CMakeLists.txt";
395 if(!cmSystemTools::SameFile(cacheStart.c_str(), currentStart.c_str()))
397 std::string message = "Error: source : ";
398 message += currentStart;
399 message += "\nDoes not match source used to generate cache: ";
400 message += cacheStart;
401 message += "\nRe-run cmake with a different source directory.";
402 cmSystemTools::Error(message.c_str());
403 return -2;
406 mf.AddCacheDefinition("CMAKE_HOME_DIRECTORY", mf.GetHomeDirectory(),
407 "Start directory with the top level CMakeLists.txt file for this project",
408 cmCacheManager::INTERNAL);
410 // extract command line arguments that might add cache entries
411 this->SetCacheArgs(mf, args);
413 // no generator specified on the command line
414 if(!mf.GetMakefileGenerator())
416 cmMakefileGenerator* gen;
417 const char* genName = mf.GetDefinition("CMAKE_GENERATOR");
418 if(genName)
420 gen = cmMakefileGenerator::CreateGenerator(genName);
422 else
424 #if defined(__BORLANDC__)
425 gen = new cmBorlandMakefileGenerator;
426 #elif defined(_WIN32) && !defined(__CYGWIN__)
427 gen = new cmMSProjectGenerator;
428 #else
429 gen = new cmUnixMakefileGenerator;
430 #endif
432 if(!gen)
434 cmSystemTools::Error("Could not create generator");
435 return -1;
437 mf.SetMakefileGenerator(gen);
438 // add the
440 cmMakefileGenerator* gen = mf.GetMakefileGenerator();
441 gen->SetLocal(m_Local);
442 const char* genName = mf.GetDefinition("CMAKE_GENERATOR");
443 if(genName)
445 if(strcmp(gen->GetName(), genName) != 0)
447 std::string message = "Error: generator : ";
448 message += gen->GetName();
449 message += "\nDoes not match the generator used previously: ";
450 message += genName;
451 message +=
452 "\nEither remove the CMakeCache.txt file or choose a different"
453 " binary directory.";
454 cmSystemTools::Error(message.c_str());
455 return -2;
458 if(!mf.GetDefinition("CMAKE_GENERATOR"))
460 mf.AddCacheDefinition("CMAKE_GENERATOR",
461 gen->GetName(),
462 "Name of generator.",
463 cmCacheManager::INTERNAL);
467 // setup CMAKE_ROOT and CMAKE_COMMAND
468 if(!this->AddCMakePaths(args))
470 return -3;
473 // reset any system configuration information
474 cmMakefileGenerator::ClearEnabledLanguages();
476 std::string lf = mf.GetStartDirectory();
477 lf += "/CMakeLists.txt";
478 if(!mf.ReadListFile(lf.c_str()))
480 this->Usage(args[0].c_str());
481 return -1;
483 // if buildMakefiles, then call GenerateMakefile
484 if(buildMakefiles)
486 mf.GenerateMakefile();
488 else // do not build, but let the commands finalize
490 std::vector<cmMakefile*> makefiles;
491 mf.FindSubDirectoryCMakeListsFiles(makefiles);
492 for(std::vector<cmMakefile*>::iterator i = makefiles.begin();
493 i != makefiles.end(); ++i)
495 cmMakefile* mf = *i;
496 mf->FinalPass();
497 delete mf;
499 mf.FinalPass();
503 // Before saving the cache
504 // if the project did not define one of the entries below, add them now
505 // so users can edit the values in the cache:
506 // LIBRARY_OUTPUT_PATH
507 // EXECUTABLE_OUTPUT_PATH
508 if(!cmCacheManager::GetInstance()->GetCacheValue("LIBRARY_OUTPUT_PATH"))
510 cmCacheManager::GetInstance()->AddCacheEntry("LIBRARY_OUTPUT_PATH", "",
511 "Single output directory for building all libraries.",
512 cmCacheManager::PATH);
514 if(!cmCacheManager::GetInstance()->GetCacheValue("EXECUTABLE_OUTPUT_PATH"))
516 cmCacheManager::GetInstance()->AddCacheEntry("EXECUTABLE_OUTPUT_PATH", "",
517 "Single output directory for building all executables.",
518 cmCacheManager::PATH);
521 cmCacheManager::GetInstance()->SaveCache(&mf);
523 if(m_Verbose)
525 cmCacheManager::GetInstance()->PrintCache(std::cout);
528 if(cmSystemTools::GetErrorOccuredFlag())
530 return -1;
532 return 0;
536 void CMakeCommandUsage(const char* program)
538 cmStringStream errorStream;
540 errorStream
541 << "cmake version " << cmMakefile::GetMajorVersion()
542 << "." << cmMakefile::GetMinorVersion() << "\n";
544 errorStream
545 << "Usage: " << program << " -E [command] [arguments ...]\n"
546 << "Available commands: \n"
547 << " chdir dir cmd [args]... - run command in a given directory\n"
548 << " copy file destination - copy file to destination (either file or directory)\n"
549 << " remove file1 file2 ... - remove the file(s)\n"
550 << " time command [args] ... - run command and return elapsed time\n";
551 #if defined(_WIN32) && !defined(__CYGWIN__)
552 errorStream
553 << " write_regv key value - write registry value\n"
554 << " delete_regv key - delete registry value\n";
555 #endif
557 cmSystemTools::Error(errorStream.str().c_str());
560 int cmake::CMakeCommand(std::vector<std::string>& args)
562 if (args.size() > 1)
564 // Copy file
565 if (args[1] == "copy" && args.size() == 4)
567 cmSystemTools::cmCopyFile(args[2].c_str(), args[3].c_str());
568 return cmSystemTools::GetErrorOccuredFlag();
571 // Remove file
572 else if (args[1] == "remove" && args.size() > 2)
574 for (std::string::size_type cc = 2; cc < args.size(); cc ++)
576 if(args[cc] != "-f")
578 if(args[cc] == "\\-f")
580 args[cc] = "-f";
582 cmSystemTools::RemoveFile(args[cc].c_str());
585 return 0;
588 // Clock command
589 else if (args[1] == "time" && args.size() > 2)
591 std::string command = args[2];
592 std::string output;
593 for (std::string::size_type cc = 3; cc < args.size(); cc ++)
595 command += " ";
596 command += args[cc];
599 clock_t clock_start, clock_finish;
600 time_t time_start, time_finish;
602 time(&time_start);
603 clock_start = clock();
605 cmSystemTools::RunCommand(command.c_str(), output, 0, true);
607 clock_finish = clock();
608 time(&time_finish);
610 std::cout << output.c_str();
612 double clocks_per_sec = (double)CLOCKS_PER_SEC;
613 std::cout << "Elapsed time: "
614 << (long)(time_finish - time_start) << " s. (time)"
615 << ", "
616 << (double)(clock_finish - clock_start) / clocks_per_sec
617 << " s. (clock)"
618 << "\n";
619 return 0;
622 // Clock command
623 else if (args[1] == "chdir" && args.size() > 2)
625 std::string directory = args[2];
626 std::string command = args[3];
627 std::string output;
628 for (std::string::size_type cc = 4; cc < args.size(); cc ++)
630 command += " ";
631 command += args[cc];
634 int retval = 0;
635 if ( cmSystemTools::RunCommand(command.c_str(), output, retval,
636 directory.c_str(), true) )
638 std::cout << output.c_str();
639 return retval;
642 return 1;
645 #if defined(_WIN32) && !defined(__CYGWIN__)
646 // Write registry value
647 else if (args[1] == "write_regv" && args.size() > 3)
649 return cmSystemTools::WriteRegistryValue(args[2].c_str(),
650 args[3].c_str()) ? 0 : 1;
653 // Delete registry value
654 else if (args[1] == "delete_regv" && args.size() > 2)
656 return cmSystemTools::DeleteRegistryValue(args[2].c_str()) ? 0 : 1;
658 #endif
661 ::CMakeCommandUsage(args[0].c_str());
662 return 1;