Coverage Report

Created: 2026-03-12 06:35

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