cpack.cxx 15.7 KB
Newer Older
1
2
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
   file Copyright.txt or https://cmake.org/licensing for details.  */
Daniel Pfeifer's avatar
Daniel Pfeifer committed
3
#include <cmConfigure.h>
4

Bill Hoffman's avatar
Bill Hoffman committed
5
#include "cmCPackGenerator.h"
6
#include "cmCPackGeneratorFactory.h"
Daniel Pfeifer's avatar
Daniel Pfeifer committed
7
#include "cmCPackLog.h"
8
#include "cmDocumentation.h"
Daniel Pfeifer's avatar
Daniel Pfeifer committed
9
#include "cmDocumentationEntry.h"
10
11
#include "cmGlobalGenerator.h"
#include "cmMakefile.h"
12
#include "cmState.h"
13
#include "cmStateTypes.h"
Daniel Pfeifer's avatar
Daniel Pfeifer committed
14
15
16
#include "cmSystemTools.h"
#include "cmTypeMacro.h"
#include "cm_auto_ptr.hxx"
17
#include "cmake.h"
18

19
#include <cmsys/CommandLineArguments.hxx>
20
#include <cmsys/Encoding.hxx>
Daniel Pfeifer's avatar
Daniel Pfeifer committed
21
22
23
24
25
26
27
#include <iostream>
#include <map>
#include <sstream>
#include <stddef.h>
#include <string>
#include <utility>
#include <vector>
28

29
static const char* cmDocumentationName[][2] = {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
30
31
  { CM_NULLPTR, "  cpack - Packaging driver provided by CMake." },
  { CM_NULLPTR, CM_NULLPTR }
32
33
};

34
static const char* cmDocumentationUsage[][2] = {
Daniel Pfeifer's avatar
Daniel Pfeifer committed
35
36
  { CM_NULLPTR, "  cpack -G <generator> [options]" },
  { CM_NULLPTR, CM_NULLPTR }
37
38
};

39
40
41
42
43
44
45
46
47
48
49
static const char* cmDocumentationOptions[][2] = {
  { "-G <generator>", "Use the specified generator to generate package." },
  { "-C <Configuration>", "Specify the project configuration" },
  { "-D <var>=<value>", "Set a CPack variable." },
  { "--config <config file>", "Specify the config file." },
  { "--verbose,-V", "enable verbose output" },
  { "--debug", "enable debug output (for CPack developers)" },
  { "-P <package name>", "override/define CPACK_PACKAGE_NAME" },
  { "-R <package version>", "override/define CPACK_PACKAGE_VERSION" },
  { "-B <package directory>", "override/define CPACK_PACKAGE_DIRECTORY" },
  { "--vendor <vendor name>", "override/define CPACK_PACKAGE_VENDOR" },
Daniel Pfeifer's avatar
Daniel Pfeifer committed
50
  { CM_NULLPTR, CM_NULLPTR }
51
52
};

53
int cpackUnknownArgument(const char* /*unused*/, void* /*unused*/)
54
55
56
57
{
  return 1;
}

58
59
struct cpackDefinitions
{
60
  typedef std::map<std::string, std::string> MapType;
Andy Cedilnik's avatar
Andy Cedilnik committed
61
  MapType Map;
62
  cmCPackLog* Log;
63
};
64

Andy Cedilnik's avatar
Andy Cedilnik committed
65
int cpackDefinitionArgument(const char* argument, const char* cValue,
66
                            void* call_data)
67
68
{
  (void)argument;
69
  cpackDefinitions* def = static_cast<cpackDefinitions*>(call_data);
70
  std::string value = cValue;
71
  size_t pos = value.find_first_of('=');
72
  if (pos == std::string::npos) {
Andy Cedilnik's avatar
Andy Cedilnik committed
73
    cmCPack_Log(def->Log, cmCPackLog::LOG_ERROR,
74
                "Please specify CPack definitions as: KEY=VALUE" << std::endl);
75
    return 0;
76
  }
77
78
  std::string key = value.substr(0, pos);
  value = value.c_str() + pos + 1;
Andy Cedilnik's avatar
Andy Cedilnik committed
79
80
  def->Map[key] = value;
  cmCPack_Log(def->Log, cmCPackLog::LOG_DEBUG, "Set CPack variable: "
81
                << key << " to \"" << value << "\"" << std::endl);
82
83
84
85
  return 1;
}

// this is CPack.
86
int main(int argc, char const* const* argv)
87
{
88
89
90
91
92
  cmsys::Encoding::CommandLineArguments args =
    cmsys::Encoding::CommandLineArguments::Main(argc, argv);
  argc = args.argc();
  argv = args.argv();

93
  cmSystemTools::FindCMakeResources(argv[0]);
94
  cmCPackLog log;
95

96
97
98
  log.SetErrorPrefix("CPack Error: ");
  log.SetWarningPrefix("CPack Warning: ");
  log.SetOutputPrefix("CPack: ");
99
  log.SetVerbosePrefix("CPack Verbose: ");
100

101
102
  cmSystemTools::EnableMSVCDebugHook();

103
  if (cmSystemTools::GetCurrentWorkingDirectory().empty()) {
104
    cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
105
106
                "Current working directory cannot be established."
                  << std::endl);
107
    return 1;
108
  }
109
110
111
112

  std::string generator;
  bool help = false;
  bool helpVersion = false;
113
114
  bool verbose = false;
  bool debug = false;
115
116
117
118
119
  std::string helpFull;
  std::string helpMAN;
  std::string helpHTML;

  std::string cpackProjectName;
120
  std::string cpackProjectDirectory;
121
122
123
124
  std::string cpackBuildConfig;
  std::string cpackProjectVersion;
  std::string cpackProjectPatch;
  std::string cpackProjectVendor;
125
126
127
  std::string cpackConfigFile;

  cpackDefinitions definitions;
Andy Cedilnik's avatar
Andy Cedilnik committed
128
  definitions.Log = &log;
129

130
  cpackConfigFile = "";
131
132
133
134
135
136

  cmsys::CommandLineArguments arg;
  arg.Initialize(argc, argv);
  typedef cmsys::CommandLineArguments argT;
  // Help arguments
  arg.AddArgument("--help", argT::NO_ARGUMENT, &help, "CPack help");
Andy Cedilnik's avatar
Andy Cedilnik committed
137
  arg.AddArgument("--help-full", argT::SPACE_ARGUMENT, &helpFull,
138
                  "CPack help");
Andy Cedilnik's avatar
Andy Cedilnik committed
139
  arg.AddArgument("--help-html", argT::SPACE_ARGUMENT, &helpHTML,
140
                  "CPack help");
141
142
143
  arg.AddArgument("--help-man", argT::SPACE_ARGUMENT, &helpMAN, "CPack help");
  arg.AddArgument("--version", argT::NO_ARGUMENT, &helpVersion, "CPack help");

144
145
146
  arg.AddArgument("-V", argT::NO_ARGUMENT, &verbose, "CPack verbose");
  arg.AddArgument("--verbose", argT::NO_ARGUMENT, &verbose, "-V");
  arg.AddArgument("--debug", argT::NO_ARGUMENT, &debug, "-V");
147
  arg.AddArgument("--config", argT::SPACE_ARGUMENT, &cpackConfigFile,
148
                  "CPack configuration file");
149
  arg.AddArgument("-C", argT::SPACE_ARGUMENT, &cpackBuildConfig,
150
151
152
153
154
155
156
157
158
159
160
161
162
163
                  "CPack build configuration");
  arg.AddArgument("-G", argT::SPACE_ARGUMENT, &generator, "CPack generator");
  arg.AddArgument("-P", argT::SPACE_ARGUMENT, &cpackProjectName,
                  "CPack project name");
  arg.AddArgument("-R", argT::SPACE_ARGUMENT, &cpackProjectVersion,
                  "CPack project version");
  arg.AddArgument("-B", argT::SPACE_ARGUMENT, &cpackProjectDirectory,
                  "CPack project directory");
  arg.AddArgument("--patch", argT::SPACE_ARGUMENT, &cpackProjectPatch,
                  "CPack project patch");
  arg.AddArgument("--vendor", argT::SPACE_ARGUMENT, &cpackProjectVendor,
                  "CPack project vendor");
  arg.AddCallback("-D", argT::SPACE_ARGUMENT, cpackDefinitionArgument,
                  &definitions, "CPack Definitions");
164
165
  arg.SetUnknownArgumentCallback(cpackUnknownArgument);

166
  // Parse command line
167
168
  int parsed = arg.Parse();

169
  // Setup logging
170
  if (verbose) {
171
    log.SetVerbose(verbose);
172
    cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Verbose" << std::endl);
173
174
  }
  if (debug) {
175
176
    log.SetDebug(debug);
    cmCPack_Log(&log, cmCPackLog::LOG_OUTPUT, "Enable Debug" << std::endl);
177
  }
178

179
  cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
180
              "Read CPack config file: " << cpackConfigFile << std::endl);
181

182
  cmake cminst;
183
184
  cminst.SetHomeDirectory("");
  cminst.SetHomeOutputDirectory("");
185
  cminst.GetCurrentSnapshot().SetDefaultDefinitions();
186
  cminst.GetState()->RemoveUnscriptableCommands();
187
  cmGlobalGenerator cmgg(&cminst);
188
  CM_AUTO_PTR<cmMakefile> globalMF(
189
    new cmMakefile(&cmgg, cminst.GetCurrentSnapshot()));
190
191
192
#if defined(__CYGWIN__)
  globalMF->AddDefinition("CMAKE_LEGACY_CYGWIN_WIN32", "0");
#endif
193
194

  bool cpackConfigFileSpecified = true;
195
  if (cpackConfigFile.empty()) {
196
    cpackConfigFile = cmSystemTools::GetCurrentWorkingDirectory();
197
    cpackConfigFile += "/CPackConfig.cmake";
198
    cpackConfigFileSpecified = false;
199
  }
200

Bill Hoffman's avatar
Bill Hoffman committed
201
  cmCPackGeneratorFactory generators;
202
  generators.SetLogger(&log);
Daniel Pfeifer's avatar
Daniel Pfeifer committed
203
  cmCPackGenerator* cpackGenerator = CM_NULLPTR;
204

205
206
  cmDocumentation doc;
  doc.addCPackStandardDocSections();
207
208
209
210
211
  /* Were we invoked to display doc or to do some work ?
   * Unlike cmake launching cpack with zero argument
   * should launch cpack using "cpackConfigFile" if it exists
   * in the current directory.
   */
Daniel Pfeifer's avatar
Daniel Pfeifer committed
212
  help = doc.CheckOptions(argc, argv, "-G") && argc != 1;
213

214
215
  // This part is used for cpack documentation lookup as well.
  cminst.AddCMakePaths();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
216

217
  if (parsed && !help) {
218
219
220
221
    // find out which system cpack is running on, so it can setup the search
    // paths, so FIND_XXX() commands can be used in scripts
    std::string systemFile =
      globalMF->GetModulesFile("CMakeDetermineSystem.cmake");
222
    if (!globalMF->ReadListFile(systemFile.c_str())) {
223
      cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
224
                  "Error reading CMakeDetermineSystem.cmake" << std::endl);
225
      return 1;
226
    }
227
228
229

    systemFile =
      globalMF->GetModulesFile("CMakeSystemSpecificInformation.cmake");
230
    if (!globalMF->ReadListFile(systemFile.c_str())) {
231
      cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
232
233
                  "Error reading CMakeSystemSpecificInformation.cmake"
                    << std::endl);
234
      return 1;
235
    }
236

237
    if (!cpackBuildConfig.empty()) {
238
      globalMF->AddDefinition("CPACK_BUILD_CONFIG", cpackBuildConfig.c_str());
239
    }
240

241
242
    if (cmSystemTools::FileExists(cpackConfigFile.c_str())) {
      cpackConfigFile = cmSystemTools::CollapseFullPath(cpackConfigFile);
243
      cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
244
245
246
                  "Read CPack configuration file: " << cpackConfigFile
                                                    << std::endl);
      if (!globalMF->ReadListFile(cpackConfigFile.c_str())) {
247
        cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
248
249
                    "Problem reading CPack config file: \""
                      << cpackConfigFile << "\"" << std::endl);
250
        return 1;
251
      }
252
    } else if (cpackConfigFileSpecified) {
253
      cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
254
255
                  "Cannot find CPack config file: \"" << cpackConfigFile
                                                      << "\"" << std::endl);
256
      return 1;
257
    }
258

259
    if (!generator.empty()) {
260
      globalMF->AddDefinition("CPACK_GENERATOR", generator.c_str());
261
262
    }
    if (!cpackProjectName.empty()) {
263
      globalMF->AddDefinition("CPACK_PACKAGE_NAME", cpackProjectName.c_str());
264
265
    }
    if (!cpackProjectVersion.empty()) {
Andy Cedilnik's avatar
Andy Cedilnik committed
266
      globalMF->AddDefinition("CPACK_PACKAGE_VERSION",
267
268
269
                              cpackProjectVersion.c_str());
    }
    if (!cpackProjectVendor.empty()) {
Andy Cedilnik's avatar
Andy Cedilnik committed
270
      globalMF->AddDefinition("CPACK_PACKAGE_VENDOR",
271
272
                              cpackProjectVendor.c_str());
    }
273
274
    // if this is not empty it has been set on the command line
    // go for it. Command line override values set in config file.
275
    if (!cpackProjectDirectory.empty()) {
276
      globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
277
                              cpackProjectDirectory.c_str());
278
    }
279
    // The value has not been set on the command line
280
    else {
281
282
283
      // get a default value (current working directory)
      cpackProjectDirectory = cmsys::SystemTools::GetCurrentWorkingDirectory();
      // use default value iff no value has been provided by the config file
284
      if (!globalMF->IsSet("CPACK_PACKAGE_DIRECTORY")) {
285
286
        globalMF->AddDefinition("CPACK_PACKAGE_DIRECTORY",
                                cpackProjectDirectory.c_str());
287
      }
288
    }
289
    cpackDefinitions::MapType::iterator cdit;
290
291
    for (cdit = definitions.Map.begin(); cdit != definitions.Map.end();
         ++cdit) {
Stephen Kelly's avatar
Stephen Kelly committed
292
      globalMF->AddDefinition(cdit->first, cdit->second.c_str());
293
    }
294

Brad King's avatar
Brad King committed
295
296
    const char* cpackModulesPath =
      globalMF->GetDefinition("CPACK_MODULE_PATH");
297
    if (cpackModulesPath) {
298
      globalMF->AddDefinition("CMAKE_MODULE_PATH", cpackModulesPath);
299
    }
300
    const char* genList = globalMF->GetDefinition("CPACK_GENERATOR");
301
302
303
304
    if (!genList) {
      cmCPack_Log(&log, cmCPackLog::LOG_ERROR, "CPack generator not specified"
                    << std::endl);
    } else {
Andy Cedilnik's avatar
Andy Cedilnik committed
305
      std::vector<std::string> generatorsVector;
306
      cmSystemTools::ExpandListArgument(genList, generatorsVector);
Andy Cedilnik's avatar
Andy Cedilnik committed
307
      std::vector<std::string>::iterator it;
308
      for (it = generatorsVector.begin(); it != generatorsVector.end(); ++it) {
Andy Cedilnik's avatar
Andy Cedilnik committed
309
        const char* gen = it->c_str();
310
311
        cmMakefile::ScopePushPop raii(globalMF.get());
        cmMakefile* mf = globalMF.get();
Alexander Neundorf's avatar
   
Alexander Neundorf committed
312
        cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
313
314
                    "Specified generator: " << gen << std::endl);
        if (parsed && !mf->GetDefinition("CPACK_PACKAGE_NAME")) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
315
          cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
316
                      "CPack project name not specified" << std::endl);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
317
          parsed = 0;
318
        }
319
320
321
322
        if (parsed &&
            !(mf->GetDefinition("CPACK_PACKAGE_VERSION") ||
              (mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR") &&
               mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR") &&
323
               mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH")))) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
324
          cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
325
326
327
328
329
330
331
                      "CPack project version not specified"
                        << std::endl
                        << "Specify CPACK_PACKAGE_VERSION, or "
                           "CPACK_PACKAGE_VERSION_MAJOR, "
                           "CPACK_PACKAGE_VERSION_MINOR, and "
                           "CPACK_PACKAGE_VERSION_PATCH."
                        << std::endl);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
332
          parsed = 0;
333
334
        }
        if (parsed) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
335
          cpackGenerator = generators.NewGenerator(gen);
336
          if (!cpackGenerator) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
337
            cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
338
339
                        "Cannot initialize CPack generator: " << gen
                                                              << std::endl);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
340
            parsed = 0;
341
342
          }
          if (parsed && !cpackGenerator->Initialize(gen, mf)) {
343
            cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
344
345
                        "Cannot initialize the generator " << gen
                                                           << std::endl);
346
            parsed = 0;
347
          }
Alexander Neundorf's avatar
   
Alexander Neundorf committed
348

349
350
351
352
353
          if (!mf->GetDefinition("CPACK_INSTALL_COMMANDS") &&
              !mf->GetDefinition("CPACK_INSTALLED_DIRECTORIES") &&
              !mf->GetDefinition("CPACK_INSTALL_CMAKE_PROJECTS")) {
            cmCPack_Log(
              &log, cmCPackLog::LOG_ERROR,
Alexander Neundorf's avatar
   
Alexander Neundorf committed
354
355
356
357
              "Please specify build tree of the project that uses CMake "
              "using CPACK_INSTALL_CMAKE_PROJECTS, specify "
              "CPACK_INSTALL_COMMANDS, or specify "
              "CPACK_INSTALLED_DIRECTORIES."
358
                << std::endl);
359
            parsed = 0;
360
361
          }
          if (parsed) {
Alexander Neundorf's avatar
   
Alexander Neundorf committed
362
363
            const char* projName = mf->GetDefinition("CPACK_PACKAGE_NAME");
            cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE, "Use generator: "
364
365
366
                          << cpackGenerator->GetNameOfClass() << std::endl);
            cmCPack_Log(&log, cmCPackLog::LOG_VERBOSE,
                        "For project: " << projName << std::endl);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
367

368
            const char* projVersion =
Alexander Neundorf's avatar
   
Alexander Neundorf committed
369
              mf->GetDefinition("CPACK_PACKAGE_VERSION");
370
371
372
373
374
375
376
            if (!projVersion) {
              const char* projVersionMajor =
                mf->GetDefinition("CPACK_PACKAGE_VERSION_MAJOR");
              const char* projVersionMinor =
                mf->GetDefinition("CPACK_PACKAGE_VERSION_MINOR");
              const char* projVersionPatch =
                mf->GetDefinition("CPACK_PACKAGE_VERSION_PATCH");
377
              std::ostringstream ostr;
Alexander Neundorf's avatar
   
Alexander Neundorf committed
378
              ostr << projVersionMajor << "." << projVersionMinor << "."
379
380
381
                   << projVersionPatch;
              mf->AddDefinition("CPACK_PACKAGE_VERSION", ostr.str().c_str());
            }
Andy Cedilnik's avatar
Andy Cedilnik committed
382

383
            int res = cpackGenerator->DoPackage();
384
            if (!res) {
Andy Cedilnik's avatar
Andy Cedilnik committed
385
              cmCPack_Log(&log, cmCPackLog::LOG_ERROR,
386
387
                          "Error when generating package: " << projName
                                                            << std::endl);
Alexander Neundorf's avatar
   
Alexander Neundorf committed
388
              return 1;
389
390
            }
          }
391
        }
Andy Cedilnik's avatar
Andy Cedilnik committed
392
393
      }
    }
394
  }
395

396
397
398
399
  /* In this case we are building the documentation object
   * instance in order to create appropriate structure
   * in order to satisfy the appropriate --help-xxx request
   */
400
  if (help) {
Andy Cedilnik's avatar
Andy Cedilnik committed
401
    // Construct and print requested documentation.
402

Andy Cedilnik's avatar
Andy Cedilnik committed
403
    doc.SetName("cpack");
404
405
406
    doc.SetSection("Name", cmDocumentationName);
    doc.SetSection("Usage", cmDocumentationUsage);
    doc.PrependSection("Options", cmDocumentationOptions);
Andy Cedilnik's avatar
Andy Cedilnik committed
407
408

    std::vector<cmDocumentationEntry> v;
Bill Hoffman's avatar
Bill Hoffman committed
409
    cmCPackGeneratorFactory::DescriptionsMap::const_iterator generatorIt;
410
411
    for (generatorIt = generators.GetGeneratorsList().begin();
         generatorIt != generators.GetGeneratorsList().end(); ++generatorIt) {
Andy Cedilnik's avatar
Andy Cedilnik committed
412
      cmDocumentationEntry e;
413
414
      e.Name = generatorIt->first;
      e.Brief = generatorIt->second;
Andy Cedilnik's avatar
Andy Cedilnik committed
415
      v.push_back(e);
416
417
    }
    doc.SetSection("Generators", v);
418

419
420
    return doc.PrintRequestedDocumentation(std::cout) ? 0 : 1;
  }
421

422
  if (cmSystemTools::GetErrorOccuredFlag()) {
423
    return 1;
424
  }
425

426
427
  return 0;
}