Coverage Report

Created: 2026-02-09 06:05

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmInstallGenerator.cxx
Line
Count
Source
1
/* Distributed under the OSI-approved BSD 3-Clause License.  See accompanying
2
   file LICENSE.rst or https://cmake.org/licensing for details.  */
3
#include "cmInstallGenerator.h"
4
5
#include <sstream>
6
#include <utility>
7
8
#if __cplusplus >= 201703L || defined(_MSVC_LANG) && _MSVC_LANG >= 201703L
9
#  include <string_view> // To fix IWYU warning
10
#endif
11
12
#include "cmMakefile.h"
13
#include "cmStringAlgorithms.h"
14
#include "cmSystemTools.h"
15
16
cmInstallGenerator::cmInstallGenerator(
17
  std::string destination, std::vector<std::string> const& configurations,
18
  std::string component, MessageLevel message, bool exclude_from_all,
19
  bool all_components, cmListFileBacktrace backtrace)
20
0
  : cmScriptGenerator("CMAKE_INSTALL_CONFIG_NAME", configurations)
21
0
  , Destination(std::move(destination))
22
0
  , Component(std::move(component))
23
0
  , Message(message)
24
0
  , ExcludeFromAll(exclude_from_all)
25
0
  , AllComponents(all_components)
26
0
  , Backtrace(std::move(backtrace))
27
0
{
28
0
}
29
30
0
cmInstallGenerator::~cmInstallGenerator() = default;
31
32
bool cmInstallGenerator::HaveInstall()
33
0
{
34
0
  return true;
35
0
}
36
37
void cmInstallGenerator::CheckCMP0082(bool& haveSubdirectoryInstall,
38
                                      bool& haveInstallAfterSubdirectory)
39
0
{
40
0
  if (haveSubdirectoryInstall) {
41
0
    haveInstallAfterSubdirectory = true;
42
0
  }
43
0
}
44
45
void cmInstallGenerator::AddInstallRule(
46
  std::ostream& os, std::string const& dest, cmInstallType type,
47
  std::vector<std::string> const& files, bool optional /* = false */,
48
  char const* permissions_file /* = nullptr */,
49
  char const* permissions_dir /* = nullptr */,
50
  char const* rename /* = nullptr */, char const* literal_args /* = nullptr */,
51
  Indent indent, char const* files_var /* = nullptr */)
52
0
{
53
  // Use the FILE command to install the file.
54
0
  std::string stype;
55
0
  switch (type) {
56
0
    case cmInstallType_DIRECTORY:
57
0
      stype = "DIRECTORY";
58
0
      break;
59
0
    case cmInstallType_PROGRAMS:
60
0
      stype = "PROGRAM";
61
0
      break;
62
0
    case cmInstallType_EXECUTABLE:
63
0
      stype = "EXECUTABLE";
64
0
      break;
65
0
    case cmInstallType_STATIC_LIBRARY:
66
0
      stype = "STATIC_LIBRARY";
67
0
      break;
68
0
    case cmInstallType_SHARED_LIBRARY:
69
0
      stype = "SHARED_LIBRARY";
70
0
      break;
71
0
    case cmInstallType_MODULE_LIBRARY:
72
0
      stype = "MODULE";
73
0
      break;
74
0
    case cmInstallType_FILES:
75
0
      stype = "FILE";
76
0
      break;
77
0
  }
78
0
  if (cmSystemTools::FileIsFullPath(dest)) {
79
0
    if (!files.empty()) {
80
0
      os << indent << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES\n";
81
0
      os << indent << " \"";
82
0
      bool firstIteration = true;
83
0
      for (std::string const& file : files) {
84
0
        if (!firstIteration) {
85
0
          os << ";";
86
0
        }
87
0
        os << dest << "/";
88
0
        if (rename && *rename) {
89
0
          os << rename;
90
0
        } else {
91
0
          os << cmSystemTools::GetFilenameNameView(file);
92
0
        }
93
0
        firstIteration = false;
94
0
      }
95
0
      os << "\")\n";
96
0
    }
97
0
    if (files_var) {
98
0
      os << indent << "foreach(_cmake_abs_file IN LISTS " << files_var
99
0
         << ")\n";
100
0
      os << indent.Next()
101
0
         << "get_filename_component(_cmake_abs_file_name "
102
0
            "\"${_cmake_abs_file}\" NAME)\n";
103
0
      os << indent.Next() << "list(APPEND CMAKE_ABSOLUTE_DESTINATION_FILES \""
104
0
         << dest << "/${_cmake_abs_file_name}\")\n";
105
0
      os << indent << "endforeach()\n";
106
0
      os << indent << "unset(_cmake_abs_file_name)\n";
107
0
      os << indent << "unset(_cmake_abs_file)\n";
108
0
    }
109
0
    os << indent << "if(CMAKE_WARN_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
110
0
    os << indent.Next()
111
0
       << "message(WARNING \"ABSOLUTE path INSTALL "
112
0
          "DESTINATION : ${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
113
0
    os << indent << "endif()\n";
114
115
0
    os << indent << "if(CMAKE_ERROR_ON_ABSOLUTE_INSTALL_DESTINATION)\n";
116
0
    os << indent.Next()
117
0
       << "message(FATAL_ERROR \"ABSOLUTE path INSTALL "
118
0
          "DESTINATION forbidden (by caller): "
119
0
          "${CMAKE_ABSOLUTE_DESTINATION_FILES}\")\n";
120
0
    os << indent << "endif()\n";
121
0
  }
122
0
  std::string absDest = ConvertToAbsoluteDestination(dest);
123
0
  os << indent << "file(INSTALL DESTINATION \"" << absDest << "\" TYPE "
124
0
     << stype;
125
0
  if (optional) {
126
0
    os << " OPTIONAL";
127
0
  }
128
0
  switch (this->Message) {
129
0
    case MessageDefault:
130
0
      break;
131
0
    case MessageAlways:
132
0
      os << " MESSAGE_ALWAYS";
133
0
      break;
134
0
    case MessageLazy:
135
0
      os << " MESSAGE_LAZY";
136
0
      break;
137
0
    case MessageNever:
138
0
      os << " MESSAGE_NEVER";
139
0
      break;
140
0
  }
141
0
  if (permissions_file && *permissions_file) {
142
0
    os << " PERMISSIONS" << permissions_file;
143
0
  }
144
0
  if (permissions_dir && *permissions_dir) {
145
0
    os << " DIR_PERMISSIONS" << permissions_dir;
146
0
  }
147
0
  if (rename && *rename) {
148
0
    os << " RENAME \"" << rename << "\"";
149
0
  }
150
0
  os << " FILES";
151
0
  if (files.size() == 1) {
152
0
    os << " \"" << files[0] << "\"";
153
0
  } else {
154
0
    for (std::string const& f : files) {
155
0
      os << "\n" << indent << "  \"" << f << "\"";
156
0
    }
157
0
    if (files_var) {
158
0
      os << " ${" << files_var << "}";
159
0
    }
160
0
    os << "\n" << indent << " ";
161
0
    if (!(literal_args && *literal_args)) {
162
0
      os << " ";
163
0
    }
164
0
  }
165
0
  if (literal_args && *literal_args) {
166
0
    os << literal_args;
167
0
  }
168
0
  os << ")\n";
169
0
}
170
171
std::string cmInstallGenerator::CreateComponentTest(
172
  std::string const& component, bool exclude_from_all, bool all_components)
173
0
{
174
0
  if (all_components) {
175
0
    if (exclude_from_all) {
176
0
      return "CMAKE_INSTALL_COMPONENT";
177
0
    }
178
0
    return {};
179
0
  }
180
181
0
  std::string result = "CMAKE_INSTALL_COMPONENT STREQUAL \"";
182
0
  result += component;
183
0
  result += "\"";
184
0
  if (!exclude_from_all) {
185
0
    result += " OR NOT CMAKE_INSTALL_COMPONENT";
186
0
  }
187
188
0
  return result;
189
0
}
190
191
void cmInstallGenerator::GenerateScript(std::ostream& os)
192
0
{
193
  // Track indentation.
194
0
  Indent indent;
195
196
0
  std::string component_test = this->CreateComponentTest(
197
0
    this->Component, this->ExcludeFromAll, this->AllComponents);
198
199
  // Begin this block of installation.
200
0
  if (!component_test.empty()) {
201
0
    os << indent << "if(" << component_test << ")\n";
202
0
  }
203
204
  // Generate the script possibly with per-configuration code.
205
0
  this->GenerateScriptConfigs(os,
206
0
                              this->AllComponents ? indent : indent.Next());
207
208
  // End this block of installation.
209
0
  if (!component_test.empty()) {
210
0
    os << indent << "endif()\n\n";
211
0
  }
212
0
}
213
214
bool cmInstallGenerator::InstallsForConfig(std::string const& config)
215
0
{
216
0
  return this->GeneratesForConfig(config);
217
0
}
218
219
std::string cmInstallGenerator::ConvertToAbsoluteDestination(
220
  std::string const& dest)
221
0
{
222
0
  std::string result;
223
0
  if (!dest.empty() && !cmSystemTools::FileIsFullPath(dest)) {
224
0
    result = "${CMAKE_INSTALL_PREFIX}/";
225
0
  }
226
0
  result += dest;
227
0
  return result;
228
0
}
229
230
cmInstallGenerator::MessageLevel cmInstallGenerator::SelectMessageLevel(
231
  cmMakefile* mf, bool never)
232
0
{
233
0
  if (never) {
234
0
    return MessageNever;
235
0
  }
236
0
  std::string m = mf->GetSafeDefinition("CMAKE_INSTALL_MESSAGE");
237
0
  if (m == "ALWAYS") {
238
0
    return MessageAlways;
239
0
  }
240
0
  if (m == "LAZY") {
241
0
    return MessageLazy;
242
0
  }
243
0
  if (m == "NEVER") {
244
0
    return MessageNever;
245
0
  }
246
0
  return MessageDefault;
247
0
}
248
249
std::string cmInstallGenerator::GetDestDirPath(std::string const& file)
250
0
{
251
  // Construct the path of the file on disk after installation on
252
  // which tweaks may be performed.
253
0
  std::string toDestDirPath = "$ENV{DESTDIR}";
254
0
  if (file[0] != '/' && file[0] != '$') {
255
0
    toDestDirPath += "/";
256
0
  }
257
0
  toDestDirPath += file;
258
0
  return toDestDirPath;
259
0
}
260
261
void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent,
262
                                  std::string const& config,
263
                                  std::string const& file,
264
                                  TweakMethod const& tweak)
265
0
{
266
0
  std::ostringstream tw;
267
0
  tweak(tw, indent.Next(), config, file);
268
0
  std::string tws = tw.str();
269
0
  if (!tws.empty()) {
270
0
    os << indent << "if(EXISTS \"" << file << "\" AND\n"
271
0
       << indent << "   NOT IS_SYMLINK \"" << file << "\")\n";
272
0
    os << tws;
273
0
    os << indent << "endif()\n";
274
0
  }
275
0
}
276
277
void cmInstallGenerator::AddTweak(std::ostream& os, Indent indent,
278
                                  std::string const& config,
279
                                  std::string const& dir,
280
                                  std::vector<std::string> const& files,
281
                                  TweakMethod const& tweak)
282
0
{
283
0
  if (files.size() == 1) {
284
    // Tweak a single file.
285
0
    AddTweak(os, indent, config, GetDestDirPath(cmStrCat(dir, files[0])),
286
0
             tweak);
287
0
  } else {
288
    // Generate a foreach loop to tweak multiple files.
289
0
    std::ostringstream tw;
290
0
    AddTweak(tw, indent.Next(), config, "${file}", tweak);
291
0
    std::string tws = tw.str();
292
0
    if (!tws.empty()) {
293
0
      Indent indent2 = indent.Next().Next();
294
0
      os << indent << "foreach(file\n";
295
0
      for (std::string const& f : files) {
296
0
        os << indent2 << "\"" << GetDestDirPath(cmStrCat(dir, f)) << "\"\n";
297
0
      }
298
0
      os << indent2 << ")\n";
299
0
      os << tws;
300
0
      os << indent << "endforeach()\n";
301
0
    }
302
0
  }
303
0
}