Coverage Report

Created: 2026-10-28 06:38

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/CMake/Source/cmGeneratorTarget_CompatibleInterface.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
/* clang-format off */
4
#include "cmGeneratorTarget.h"
5
/* clang-format on */
6
7
#include <algorithm>
8
#include <cassert>
9
#include <cerrno>
10
#include <cstddef>
11
#include <cstdlib>
12
#include <cstring>
13
#include <iterator>
14
#include <map>
15
#include <set>
16
#include <string>
17
#include <utility>
18
#include <vector>
19
20
#include <cm/memory>
21
#include <cmext/algorithm>
22
23
#include "cmComputeLinkInformation.h"
24
#include "cmGeneratorExpression.h"
25
#include "cmList.h"
26
#include "cmLocalGenerator.h"
27
#include "cmMessageType.h"
28
#include "cmRange.h"
29
#include "cmStringAlgorithms.h"
30
#include "cmSystemTools.h"
31
#include "cmTargetTypes.h"
32
#include "cmUnreachable.h"
33
#include "cmValue.h"
34
35
namespace {
36
using UseTo = cmGeneratorTarget::UseTo;
37
}
38
39
cmGeneratorTarget::CompatibleInterfacesBase const&
40
cmGeneratorTarget::GetCompatibleInterfaces(std::string const& config) const
41
26.5k
{
42
26.5k
  cmGeneratorTarget::CompatibleInterfaces& compat =
43
26.5k
    this->CompatibleInterfacesMap[config];
44
26.5k
  if (!compat.Done) {
45
4.37k
    compat.Done = true;
46
4.37k
    compat.PropsBool.insert("POSITION_INDEPENDENT_CODE");
47
4.37k
    compat.PropsString.insert("AUTOUIC_OPTIONS");
48
4.37k
    std::vector<cmGeneratorTarget const*> const& deps =
49
4.37k
      this->GetLinkImplementationClosure(config, UseTo::Compile);
50
6.66k
    for (cmGeneratorTarget const* li : deps) {
51
6.66k
#define CM_READ_COMPATIBLE_INTERFACE(X, x)                                    \
52
26.6k
  if (cmValue prop = li->GetProperty("COMPATIBLE_INTERFACE_" #X)) {           \
53
3.50k
    cmList props(*prop);                                                      \
54
3.50k
    compat.Props##x.insert(props.begin(), props.end());                       \
55
3.50k
  }
56
6.66k
      CM_READ_COMPATIBLE_INTERFACE(BOOL, Bool)
57
6.66k
      CM_READ_COMPATIBLE_INTERFACE(STRING, String)
58
6.66k
      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MIN, NumberMin)
59
6.66k
      CM_READ_COMPATIBLE_INTERFACE(NUMBER_MAX, NumberMax)
60
6.66k
#undef CM_READ_COMPATIBLE_INTERFACE
61
6.66k
    }
62
4.37k
  }
63
26.5k
  return compat;
64
26.5k
}
65
66
bool cmGeneratorTarget::IsLinkInterfaceDependentBoolProperty(
67
  std::string const& p, std::string const& config) const
68
6.41k
{
69
6.41k
  if (this->GetType() == cm::TargetType::OBJECT_LIBRARY ||
70
6.18k
      this->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
71
557
    return false;
72
557
  }
73
5.85k
  return this->GetCompatibleInterfaces(config).PropsBool.count(p) > 0;
74
6.41k
}
75
76
bool cmGeneratorTarget::IsLinkInterfaceDependentStringProperty(
77
  std::string const& p, std::string const& config) const
78
6.36k
{
79
6.36k
  if (this->GetType() == cm::TargetType::OBJECT_LIBRARY ||
80
6.14k
      this->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
81
557
    return false;
82
557
  }
83
5.81k
  return this->GetCompatibleInterfaces(config).PropsString.count(p) > 0;
84
6.36k
}
85
86
bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMinProperty(
87
  std::string const& p, std::string const& config) const
88
9.23k
{
89
9.23k
  if (this->GetType() == cm::TargetType::OBJECT_LIBRARY ||
90
9.00k
      this->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
91
1.76k
    return false;
92
1.76k
  }
93
7.46k
  return this->GetCompatibleInterfaces(config).PropsNumberMin.count(p) > 0;
94
9.23k
}
95
96
bool cmGeneratorTarget::IsLinkInterfaceDependentNumberMaxProperty(
97
  std::string const& p, std::string const& config) const
98
9.23k
{
99
9.23k
  if (this->GetType() == cm::TargetType::OBJECT_LIBRARY ||
100
9.00k
      this->GetType() == cm::TargetType::INTERFACE_LIBRARY) {
101
1.76k
    return false;
102
1.76k
  }
103
7.46k
  return this->GetCompatibleInterfaces(config).PropsNumberMax.count(p) > 0;
104
9.23k
}
105
106
enum CompatibleType
107
{
108
  BoolType,
109
  StringType,
110
  NumberMinType,
111
  NumberMaxType
112
};
113
114
template <typename PropertyType>
115
PropertyType getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
116
                                               std::string const& prop,
117
                                               std::string const& config,
118
                                               CompatibleType, PropertyType*);
119
120
template <>
121
bool getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
122
                                       std::string const& prop,
123
                                       std::string const& config,
124
                                       CompatibleType /*unused*/,
125
                                       bool* /*unused*/)
126
0
{
127
0
  return tgt->GetLinkInterfaceDependentBoolProperty(prop, config);
128
0
}
129
130
template <>
131
char const* getLinkInterfaceDependentProperty(cmGeneratorTarget const* tgt,
132
                                              std::string const& prop,
133
                                              std::string const& config,
134
                                              CompatibleType t,
135
                                              char const** /*unused*/)
136
0
{
137
0
  switch (t) {
138
0
    case BoolType:
139
0
      CM_UNREACHABLE;
140
0
      return nullptr;
141
0
    case StringType:
142
0
      return tgt->GetLinkInterfaceDependentStringProperty(prop, config);
143
0
    case NumberMinType:
144
0
      return tgt->GetLinkInterfaceDependentNumberMinProperty(prop, config);
145
0
    case NumberMaxType:
146
0
      return tgt->GetLinkInterfaceDependentNumberMaxProperty(prop, config);
147
0
  }
148
0
  CM_UNREACHABLE;
149
0
  return nullptr;
150
0
}
151
152
template <typename PropertyType>
153
void checkPropertyConsistency(cmGeneratorTarget const* depender,
154
                              cmGeneratorTarget const* dependee,
155
                              std::string const& propName,
156
                              std::set<std::string>& emitted,
157
                              std::string const& config, CompatibleType t,
158
                              PropertyType* /*unused*/)
159
0
{
160
0
  cmValue prop = dependee->GetProperty(propName);
161
0
  if (!prop) {
162
0
    return;
163
0
  }
164
165
0
  cmList props{ *prop };
166
0
  std::string pdir =
167
0
    cmStrCat(cmSystemTools::GetCMakeRoot(), "/Help/prop_tgt/");
168
169
0
  for (std::string const& p : props) {
170
0
    std::string pname = cmSystemTools::HelpFileName(p);
171
0
    std::string pfile = cmStrCat(pdir, pname, ".rst");
172
0
    if (cmSystemTools::FileExists(pfile, true)) {
173
0
      depender->GetLocalGenerator()->IssueMessage(
174
0
        MessageType::FATAL_ERROR,
175
0
        cmStrCat("Target \"", dependee->GetName(), "\" has property \"", p,
176
0
                 "\" listed in its ", propName,
177
0
                 " property.  "
178
0
                 "This is not allowed.  Only user-defined properties may "
179
0
                 "appear listed in the ",
180
0
                 propName, " property."));
181
0
      return;
182
0
    }
183
0
    if (emitted.insert(p).second) {
184
0
      getLinkInterfaceDependentProperty<PropertyType>(depender, p, config, t,
185
0
                                                      nullptr);
186
0
      if (cmSystemTools::GetErrorOccurredFlag()) {
187
0
        return;
188
0
      }
189
0
    }
190
0
  }
191
0
}
Unexecuted instantiation: void checkPropertyConsistency<bool>(cmGeneratorTarget const*, cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CompatibleType, bool*)
Unexecuted instantiation: void checkPropertyConsistency<char const*>(cmGeneratorTarget const*, cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::set<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >, std::__1::less<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >, std::__1::allocator<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > > >&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, CompatibleType, char const**)
192
193
namespace {
194
std::string intersect(std::set<std::string> const& s1,
195
                      std::set<std::string> const& s2)
196
0
{
197
0
  std::set<std::string> intersect;
198
0
  std::set_intersection(s1.begin(), s1.end(), s2.begin(), s2.end(),
199
0
                        std::inserter(intersect, intersect.begin()));
200
0
  if (!intersect.empty()) {
201
0
    return *intersect.begin();
202
0
  }
203
0
  return "";
204
0
}
205
206
std::string intersect(std::set<std::string> const& s1,
207
                      std::set<std::string> const& s2,
208
                      std::set<std::string> const& s3)
209
0
{
210
0
  std::string result;
211
0
  result = intersect(s1, s2);
212
0
  if (!result.empty()) {
213
0
    return result;
214
0
  }
215
0
  result = intersect(s1, s3);
216
0
  if (!result.empty()) {
217
0
    return result;
218
0
  }
219
0
  return intersect(s2, s3);
220
0
}
221
222
std::string intersect(std::set<std::string> const& s1,
223
                      std::set<std::string> const& s2,
224
                      std::set<std::string> const& s3,
225
                      std::set<std::string> const& s4)
226
0
{
227
0
  std::string result;
228
0
  result = intersect(s1, s2);
229
0
  if (!result.empty()) {
230
0
    return result;
231
0
  }
232
0
  result = intersect(s1, s3);
233
0
  if (!result.empty()) {
234
0
    return result;
235
0
  }
236
0
  result = intersect(s1, s4);
237
0
  if (!result.empty()) {
238
0
    return result;
239
0
  }
240
0
  return intersect(s2, s3, s4);
241
0
}
242
}
243
244
void cmGeneratorTarget::CheckPropertyCompatibility(
245
  cmComputeLinkInformation& info, std::string const& config) const
246
0
{
247
0
  cmComputeLinkInformation::ItemVector const& deps = info.GetItems();
248
249
0
  std::set<std::string> emittedBools;
250
0
  static std::string const strBool = "COMPATIBLE_INTERFACE_BOOL";
251
0
  std::set<std::string> emittedStrings;
252
0
  static std::string const strString = "COMPATIBLE_INTERFACE_STRING";
253
0
  std::set<std::string> emittedMinNumbers;
254
0
  static std::string const strNumMin = "COMPATIBLE_INTERFACE_NUMBER_MIN";
255
0
  std::set<std::string> emittedMaxNumbers;
256
0
  static std::string const strNumMax = "COMPATIBLE_INTERFACE_NUMBER_MAX";
257
258
0
  for (auto const& dep : deps) {
259
0
    if (!dep.Target ||
260
0
        dep.Target->GetType() == cm::TargetType::OBJECT_LIBRARY) {
261
0
      continue;
262
0
    }
263
264
0
    checkPropertyConsistency<bool>(this, dep.Target, strBool, emittedBools,
265
0
                                   config, BoolType, nullptr);
266
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
267
0
      return;
268
0
    }
269
0
    checkPropertyConsistency<char const*>(this, dep.Target, strString,
270
0
                                          emittedStrings, config, StringType,
271
0
                                          nullptr);
272
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
273
0
      return;
274
0
    }
275
0
    checkPropertyConsistency<char const*>(this, dep.Target, strNumMin,
276
0
                                          emittedMinNumbers, config,
277
0
                                          NumberMinType, nullptr);
278
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
279
0
      return;
280
0
    }
281
0
    checkPropertyConsistency<char const*>(this, dep.Target, strNumMax,
282
0
                                          emittedMaxNumbers, config,
283
0
                                          NumberMaxType, nullptr);
284
0
    if (cmSystemTools::GetErrorOccurredFlag()) {
285
0
      return;
286
0
    }
287
0
  }
288
289
0
  std::string prop = intersect(emittedBools, emittedStrings, emittedMinNumbers,
290
0
                               emittedMaxNumbers);
291
292
0
  if (!prop.empty()) {
293
    // Use a sorted std::vector to keep the error message sorted.
294
0
    std::vector<std::string> props;
295
0
    auto i = emittedBools.find(prop);
296
0
    if (i != emittedBools.end()) {
297
0
      props.push_back(strBool);
298
0
    }
299
0
    i = emittedStrings.find(prop);
300
0
    if (i != emittedStrings.end()) {
301
0
      props.push_back(strString);
302
0
    }
303
0
    i = emittedMinNumbers.find(prop);
304
0
    if (i != emittedMinNumbers.end()) {
305
0
      props.push_back(strNumMin);
306
0
    }
307
0
    i = emittedMaxNumbers.find(prop);
308
0
    if (i != emittedMaxNumbers.end()) {
309
0
      props.push_back(strNumMax);
310
0
    }
311
0
    std::sort(props.begin(), props.end());
312
313
0
    std::string propsString = cmStrCat(
314
0
      cmJoin(cmMakeRange(props).retreat(1), ", "), " and the ", props.back());
315
316
0
    this->LocalGenerator->IssueMessage(
317
0
      MessageType::FATAL_ERROR,
318
0
      cmStrCat("Property \"", prop, "\" appears in both the ", propsString,
319
0
               " property in the dependencies of target \"", this->GetName(),
320
0
               "\".  This is not allowed. A property may only require "
321
0
               "compatibility in a boolean interpretation, a numeric "
322
0
               "minimum, a numeric maximum or a string interpretation, but "
323
0
               "not a mixture."));
324
0
  }
325
0
}
326
327
template <typename PropertyType>
328
std::string valueAsString(PropertyType);
329
template <>
330
std::string valueAsString<bool>(bool value)
331
94
{
332
94
  return value ? "TRUE" : "FALSE";
333
94
}
334
template <>
335
std::string valueAsString<char const*>(char const* value)
336
1.75k
{
337
1.75k
  return value ? value : "(unset)";
338
1.75k
}
339
template <>
340
std::string valueAsString<std::string>(std::string value)
341
0
{
342
0
  return value;
343
0
}
344
template <>
345
std::string valueAsString<cmValue>(cmValue value)
346
0
{
347
0
  return value ? *value : std::string("(unset)");
348
0
}
349
template <>
350
std::string valueAsString<std::nullptr_t>(std::nullptr_t /*unused*/)
351
0
{
352
0
  return "(unset)";
353
0
}
354
355
static std::string compatibilityType(CompatibleType t)
356
933
{
357
933
  switch (t) {
358
47
    case BoolType:
359
47
      return "Boolean compatibility";
360
870
    case StringType:
361
870
      return "String compatibility";
362
16
    case NumberMaxType:
363
16
      return "Numeric maximum compatibility";
364
0
    case NumberMinType:
365
0
      return "Numeric minimum compatibility";
366
933
  }
367
0
  CM_UNREACHABLE;
368
0
  return "";
369
933
}
370
371
static std::string compatibilityAgree(CompatibleType t, bool dominant)
372
0
{
373
0
  switch (t) {
374
0
    case BoolType:
375
0
    case StringType:
376
0
      return dominant ? "(Disagree)\n" : "(Agree)\n";
377
0
    case NumberMaxType:
378
0
    case NumberMinType:
379
0
      return dominant ? "(Dominant)\n" : "(Ignored)\n";
380
0
  }
381
0
  CM_UNREACHABLE;
382
0
  return "";
383
0
}
384
385
template <typename PropertyType>
386
PropertyType getTypedProperty(
387
  cmGeneratorTarget const* tgt, std::string const& prop,
388
  cmGeneratorExpressionInterpreter* genexInterpreter = nullptr);
389
390
template <>
391
bool getTypedProperty<bool>(cmGeneratorTarget const* tgt,
392
                            std::string const& prop,
393
                            cmGeneratorExpressionInterpreter* genexInterpreter)
394
226
{
395
226
  if (!genexInterpreter) {
396
226
    return tgt->GetPropertyAsBool(prop);
397
226
  }
398
399
0
  cmValue value = tgt->GetProperty(prop);
400
0
  return cmIsOn(genexInterpreter->Evaluate(value ? *value : "", prop));
401
226
}
402
403
template <>
404
char const* getTypedProperty<char const*>(
405
  cmGeneratorTarget const* tgt, std::string const& prop,
406
  cmGeneratorExpressionInterpreter* genexInterpreter)
407
5.27k
{
408
5.27k
  cmValue value = tgt->GetProperty(prop);
409
410
5.27k
  if (!genexInterpreter) {
411
5.27k
    return value.GetCStr();
412
5.27k
  }
413
414
0
  return genexInterpreter->Evaluate(value ? *value : "", prop).c_str();
415
5.27k
}
416
417
template <>
418
std::string getTypedProperty<std::string>(
419
  cmGeneratorTarget const* tgt, std::string const& prop,
420
  cmGeneratorExpressionInterpreter* genexInterpreter)
421
0
{
422
0
  cmValue value = tgt->GetProperty(prop);
423
424
0
  if (!genexInterpreter) {
425
0
    return valueAsString(value);
426
0
  }
427
428
0
  return genexInterpreter->Evaluate(value ? *value : "", prop);
429
0
}
430
431
template <typename PropertyType>
432
PropertyType impliedValue(PropertyType);
433
template <>
434
bool impliedValue<bool>(bool /*unused*/)
435
0
{
436
0
  return false;
437
0
}
438
template <>
439
char const* impliedValue<char const*>(char const* /*unused*/)
440
0
{
441
0
  return "";
442
0
}
443
template <>
444
std::string impliedValue<std::string>(std::string /*unused*/) // NOLINT(*)
445
0
{
446
0
  return std::string();
447
0
}
448
449
template <typename PropertyType>
450
std::pair<bool, PropertyType> consistentProperty(PropertyType lhs,
451
                                                 PropertyType rhs,
452
                                                 CompatibleType t);
453
454
template <>
455
std::pair<bool, bool> consistentProperty(bool lhs, bool rhs,
456
                                         CompatibleType /*unused*/)
457
0
{
458
0
  return { lhs == rhs, lhs };
459
0
}
460
461
static std::pair<bool, char const*> consistentStringProperty(char const* lhs,
462
                                                             char const* rhs)
463
0
{
464
0
  bool const b = strcmp(lhs, rhs) == 0;
465
0
  return { b, b ? lhs : nullptr };
466
0
}
467
468
static std::pair<bool, std::string> consistentStringProperty(
469
  std::string const& lhs, std::string const& rhs)
470
0
{
471
0
  bool const b = lhs == rhs;
472
0
  return { b, b ? lhs : valueAsString(nullptr) };
473
0
}
474
475
static std::pair<bool, char const*> consistentNumberProperty(char const* lhs,
476
                                                             char const* rhs,
477
                                                             CompatibleType t)
478
0
{
479
0
  char* pEnd;
480
481
0
  long lnum = strtol(lhs, &pEnd, 0);
482
0
  if (pEnd == lhs || *pEnd != '\0' || errno == ERANGE) {
483
0
    return { false, nullptr };
484
0
  }
485
486
0
  long rnum = strtol(rhs, &pEnd, 0);
487
0
  if (pEnd == rhs || *pEnd != '\0' || errno == ERANGE) {
488
0
    return { false, nullptr };
489
0
  }
490
491
0
  if (t == NumberMaxType) {
492
0
    return { true, std::max(lnum, rnum) == lnum ? lhs : rhs };
493
0
  }
494
495
0
  return { true, std::min(lnum, rnum) == lnum ? lhs : rhs };
496
0
}
497
498
template <>
499
std::pair<bool, char const*> consistentProperty(char const* lhs,
500
                                                char const* rhs,
501
                                                CompatibleType t)
502
0
{
503
0
  if (!lhs && !rhs) {
504
0
    return { true, lhs };
505
0
  }
506
0
  if (!lhs) {
507
0
    return { true, rhs };
508
0
  }
509
0
  if (!rhs) {
510
0
    return { true, lhs };
511
0
  }
512
513
0
  switch (t) {
514
0
    case BoolType: {
515
0
      bool same = cmIsOn(lhs) == cmIsOn(rhs);
516
0
      return { same, same ? lhs : nullptr };
517
0
    }
518
0
    case StringType:
519
0
      return consistentStringProperty(lhs, rhs);
520
0
    case NumberMinType:
521
0
    case NumberMaxType:
522
0
      return consistentNumberProperty(lhs, rhs, t);
523
0
  }
524
0
  CM_UNREACHABLE;
525
0
  return { false, nullptr };
526
0
}
527
528
static std::pair<bool, std::string> consistentProperty(std::string const& lhs,
529
                                                       std::string const& rhs,
530
                                                       CompatibleType t)
531
0
{
532
0
  std::string const null_ptr = valueAsString(nullptr);
533
534
0
  if (lhs == null_ptr && rhs == null_ptr) {
535
0
    return { true, lhs };
536
0
  }
537
0
  if (lhs == null_ptr) {
538
0
    return { true, rhs };
539
0
  }
540
0
  if (rhs == null_ptr) {
541
0
    return { true, lhs };
542
0
  }
543
544
0
  switch (t) {
545
0
    case BoolType: {
546
0
      bool same = cmIsOn(lhs) == cmIsOn(rhs);
547
0
      return { same, same ? lhs : null_ptr };
548
0
    }
549
0
    case StringType:
550
0
      return consistentStringProperty(lhs, rhs);
551
0
    case NumberMinType:
552
0
    case NumberMaxType: {
553
0
      auto value = consistentNumberProperty(lhs.c_str(), rhs.c_str(), t);
554
0
      return { value.first,
555
0
               value.first ? std::string(value.second) : null_ptr };
556
0
    }
557
0
  }
558
0
  CM_UNREACHABLE;
559
0
  return { false, null_ptr };
560
0
}
561
562
template <typename PropertyType>
563
PropertyType checkInterfacePropertyCompatibility(cmGeneratorTarget const* tgt,
564
                                                 std::string const& p,
565
                                                 std::string const& config,
566
                                                 char const* defaultValue,
567
                                                 CompatibleType t,
568
                                                 PropertyType* /*unused*/)
569
936
{
570
936
  PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
571
572
936
  std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
573
936
  bool const explicitlySet = cm::contains(headPropKeys, p);
574
575
936
  bool const impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
576
936
  assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
577
578
936
  std::vector<cmGeneratorTarget const*> const& deps =
579
936
    tgt->GetLinkImplementationClosure(config, UseTo::Compile);
580
581
936
  if (deps.empty()) {
582
3
    return propContent;
583
3
  }
584
933
  bool propInitialized = explicitlySet;
585
586
933
  std::string report = cmStrCat(" * Target \"", tgt->GetName());
587
933
  if (explicitlySet) {
588
0
    report += "\" has property content \"";
589
0
    report += valueAsString<PropertyType>(propContent);
590
0
    report += "\"\n";
591
933
  } else if (impliedByUse) {
592
0
    report += "\" property is implied by use.\n";
593
933
  } else {
594
933
    report += "\" property not set.\n";
595
933
  }
596
597
933
  std::string interfaceProperty = "INTERFACE_" + p;
598
933
  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
599
933
  if (p == "POSITION_INDEPENDENT_CODE") {
600
    // Corresponds to EvaluatingPICExpression.
601
0
    genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
602
0
      tgt->GetLocalGenerator(), config, tgt);
603
0
  }
604
605
4.56k
  for (cmGeneratorTarget const* theTarget : deps) {
606
    // An error should be reported if one dependency
607
    // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
608
    // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
609
    // target itself has a POSITION_INDEPENDENT_CODE which disagrees
610
    // with a dependency.
611
612
4.56k
    std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
613
614
4.56k
    bool const ifaceIsSet = cm::contains(propKeys, interfaceProperty);
615
4.56k
    PropertyType ifacePropContent = getTypedProperty<PropertyType>(
616
4.56k
      theTarget, interfaceProperty, genexInterpreter.get());
617
618
4.56k
    std::string reportEntry;
619
4.56k
    if (ifaceIsSet) {
620
918
      reportEntry += " * Target \"";
621
918
      reportEntry += theTarget->GetName();
622
918
      reportEntry += "\" property value \"";
623
918
      reportEntry += valueAsString<PropertyType>(ifacePropContent);
624
918
      reportEntry += "\" ";
625
918
    }
626
627
4.56k
    if (explicitlySet) {
628
0
      if (ifaceIsSet) {
629
0
        std::pair<bool, PropertyType> consistent =
630
0
          consistentProperty(propContent, ifacePropContent, t);
631
0
        report += reportEntry;
632
0
        report += compatibilityAgree(t, propContent != consistent.second);
633
0
        if (!consistent.first) {
634
0
          cmSystemTools::Error(
635
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
636
0
                     "\" does\nnot match the INTERFACE_", p,
637
0
                     " property requirement\nof dependency \"",
638
0
                     theTarget->GetName(), "\".\n"));
639
0
          break;
640
0
        }
641
0
        propContent = consistent.second;
642
0
        continue;
643
0
      }
644
      // Explicitly set on target and not set in iface. Can't disagree.
645
0
      continue;
646
0
    }
647
4.56k
    if (impliedByUse) {
648
0
      propContent = impliedValue<PropertyType>(propContent);
649
650
0
      if (ifaceIsSet) {
651
0
        std::pair<bool, PropertyType> consistent =
652
0
          consistentProperty(propContent, ifacePropContent, t);
653
0
        report += reportEntry;
654
0
        report += compatibilityAgree(t, propContent != consistent.second);
655
0
        if (!consistent.first) {
656
0
          cmSystemTools::Error(
657
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
658
0
                     "\" is\nimplied to be ", defaultValue,
659
0
                     " because it was used to determine the link libraries\n"
660
0
                     "already. The INTERFACE_",
661
0
                     p, " property on\ndependency \"", theTarget->GetName(),
662
0
                     "\" is in conflict.\n"));
663
0
          break;
664
0
        }
665
0
        propContent = consistent.second;
666
0
        continue;
667
0
      }
668
      // Implicitly set on target and not set in iface. Can't disagree.
669
0
      continue;
670
0
    }
671
4.56k
    if (ifaceIsSet) {
672
918
      if (propInitialized) {
673
0
        std::pair<bool, PropertyType> consistent =
674
0
          consistentProperty(propContent, ifacePropContent, t);
675
0
        report =
676
0
          cmStrCat(std::move(report), reportEntry,
677
0
                   compatibilityAgree(t, propContent != consistent.second));
678
0
        if (!consistent.first) {
679
0
          cmSystemTools::Error(cmStrCat(
680
0
            "The INTERFACE_", p, " property of \"", theTarget->GetName(),
681
0
            "\" does\nnot agree with the value of ", p,
682
0
            " already determined\nfor \"", tgt->GetName(), "\".\n"));
683
0
          break;
684
0
        }
685
0
        propContent = consistent.second;
686
0
        continue;
687
0
      }
688
918
      report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n");
689
918
      propContent = ifacePropContent;
690
918
      propInitialized = true;
691
3.64k
    } else {
692
      // Not set. Nothing to agree on.
693
3.64k
      continue;
694
3.64k
    }
695
4.56k
  }
696
697
933
  tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
698
933
                            report, compatibilityType(t));
699
933
  return propContent;
700
936
}
bool checkInterfacePropertyCompatibility<bool>(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, bool*)
Line
Count
Source
569
47
{
570
47
  PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
571
572
47
  std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
573
47
  bool const explicitlySet = cm::contains(headPropKeys, p);
574
575
47
  bool const impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
576
47
  assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
577
578
47
  std::vector<cmGeneratorTarget const*> const& deps =
579
47
    tgt->GetLinkImplementationClosure(config, UseTo::Compile);
580
581
47
  if (deps.empty()) {
582
0
    return propContent;
583
0
  }
584
47
  bool propInitialized = explicitlySet;
585
586
47
  std::string report = cmStrCat(" * Target \"", tgt->GetName());
587
47
  if (explicitlySet) {
588
0
    report += "\" has property content \"";
589
0
    report += valueAsString<PropertyType>(propContent);
590
0
    report += "\"\n";
591
47
  } else if (impliedByUse) {
592
0
    report += "\" property is implied by use.\n";
593
47
  } else {
594
47
    report += "\" property not set.\n";
595
47
  }
596
597
47
  std::string interfaceProperty = "INTERFACE_" + p;
598
47
  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
599
47
  if (p == "POSITION_INDEPENDENT_CODE") {
600
    // Corresponds to EvaluatingPICExpression.
601
0
    genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
602
0
      tgt->GetLocalGenerator(), config, tgt);
603
0
  }
604
605
179
  for (cmGeneratorTarget const* theTarget : deps) {
606
    // An error should be reported if one dependency
607
    // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
608
    // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
609
    // target itself has a POSITION_INDEPENDENT_CODE which disagrees
610
    // with a dependency.
611
612
179
    std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
613
614
179
    bool const ifaceIsSet = cm::contains(propKeys, interfaceProperty);
615
179
    PropertyType ifacePropContent = getTypedProperty<PropertyType>(
616
179
      theTarget, interfaceProperty, genexInterpreter.get());
617
618
179
    std::string reportEntry;
619
179
    if (ifaceIsSet) {
620
47
      reportEntry += " * Target \"";
621
47
      reportEntry += theTarget->GetName();
622
47
      reportEntry += "\" property value \"";
623
47
      reportEntry += valueAsString<PropertyType>(ifacePropContent);
624
47
      reportEntry += "\" ";
625
47
    }
626
627
179
    if (explicitlySet) {
628
0
      if (ifaceIsSet) {
629
0
        std::pair<bool, PropertyType> consistent =
630
0
          consistentProperty(propContent, ifacePropContent, t);
631
0
        report += reportEntry;
632
0
        report += compatibilityAgree(t, propContent != consistent.second);
633
0
        if (!consistent.first) {
634
0
          cmSystemTools::Error(
635
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
636
0
                     "\" does\nnot match the INTERFACE_", p,
637
0
                     " property requirement\nof dependency \"",
638
0
                     theTarget->GetName(), "\".\n"));
639
0
          break;
640
0
        }
641
0
        propContent = consistent.second;
642
0
        continue;
643
0
      }
644
      // Explicitly set on target and not set in iface. Can't disagree.
645
0
      continue;
646
0
    }
647
179
    if (impliedByUse) {
648
0
      propContent = impliedValue<PropertyType>(propContent);
649
650
0
      if (ifaceIsSet) {
651
0
        std::pair<bool, PropertyType> consistent =
652
0
          consistentProperty(propContent, ifacePropContent, t);
653
0
        report += reportEntry;
654
0
        report += compatibilityAgree(t, propContent != consistent.second);
655
0
        if (!consistent.first) {
656
0
          cmSystemTools::Error(
657
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
658
0
                     "\" is\nimplied to be ", defaultValue,
659
0
                     " because it was used to determine the link libraries\n"
660
0
                     "already. The INTERFACE_",
661
0
                     p, " property on\ndependency \"", theTarget->GetName(),
662
0
                     "\" is in conflict.\n"));
663
0
          break;
664
0
        }
665
0
        propContent = consistent.second;
666
0
        continue;
667
0
      }
668
      // Implicitly set on target and not set in iface. Can't disagree.
669
0
      continue;
670
0
    }
671
179
    if (ifaceIsSet) {
672
47
      if (propInitialized) {
673
0
        std::pair<bool, PropertyType> consistent =
674
0
          consistentProperty(propContent, ifacePropContent, t);
675
0
        report =
676
0
          cmStrCat(std::move(report), reportEntry,
677
0
                   compatibilityAgree(t, propContent != consistent.second));
678
0
        if (!consistent.first) {
679
0
          cmSystemTools::Error(cmStrCat(
680
0
            "The INTERFACE_", p, " property of \"", theTarget->GetName(),
681
0
            "\" does\nnot agree with the value of ", p,
682
0
            " already determined\nfor \"", tgt->GetName(), "\".\n"));
683
0
          break;
684
0
        }
685
0
        propContent = consistent.second;
686
0
        continue;
687
0
      }
688
47
      report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n");
689
47
      propContent = ifacePropContent;
690
47
      propInitialized = true;
691
132
    } else {
692
      // Not set. Nothing to agree on.
693
132
      continue;
694
132
    }
695
179
  }
696
697
47
  tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
698
47
                            report, compatibilityType(t));
699
47
  return propContent;
700
47
}
Unexecuted instantiation: std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > checkInterfacePropertyCompatibility<std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > >(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> >*)
char const* checkInterfacePropertyCompatibility<char const*>(cmGeneratorTarget const*, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, std::__1::basic_string<char, std::__1::char_traits<char>, std::__1::allocator<char> > const&, char const*, CompatibleType, char const**)
Line
Count
Source
569
889
{
570
889
  PropertyType propContent = getTypedProperty<PropertyType>(tgt, p);
571
572
889
  std::vector<std::string> headPropKeys = tgt->GetPropertyKeys();
573
889
  bool const explicitlySet = cm::contains(headPropKeys, p);
574
575
889
  bool const impliedByUse = tgt->IsNullImpliedByLinkLibraries(p);
576
889
  assert((impliedByUse ^ explicitlySet) || (!impliedByUse && !explicitlySet));
577
578
889
  std::vector<cmGeneratorTarget const*> const& deps =
579
889
    tgt->GetLinkImplementationClosure(config, UseTo::Compile);
580
581
889
  if (deps.empty()) {
582
3
    return propContent;
583
3
  }
584
886
  bool propInitialized = explicitlySet;
585
586
886
  std::string report = cmStrCat(" * Target \"", tgt->GetName());
587
886
  if (explicitlySet) {
588
0
    report += "\" has property content \"";
589
0
    report += valueAsString<PropertyType>(propContent);
590
0
    report += "\"\n";
591
886
  } else if (impliedByUse) {
592
0
    report += "\" property is implied by use.\n";
593
886
  } else {
594
886
    report += "\" property not set.\n";
595
886
  }
596
597
886
  std::string interfaceProperty = "INTERFACE_" + p;
598
886
  std::unique_ptr<cmGeneratorExpressionInterpreter> genexInterpreter;
599
886
  if (p == "POSITION_INDEPENDENT_CODE") {
600
    // Corresponds to EvaluatingPICExpression.
601
0
    genexInterpreter = cm::make_unique<cmGeneratorExpressionInterpreter>(
602
0
      tgt->GetLocalGenerator(), config, tgt);
603
0
  }
604
605
4.38k
  for (cmGeneratorTarget const* theTarget : deps) {
606
    // An error should be reported if one dependency
607
    // has INTERFACE_POSITION_INDEPENDENT_CODE ON and the other
608
    // has INTERFACE_POSITION_INDEPENDENT_CODE OFF, or if the
609
    // target itself has a POSITION_INDEPENDENT_CODE which disagrees
610
    // with a dependency.
611
612
4.38k
    std::vector<std::string> propKeys = theTarget->GetPropertyKeys();
613
614
4.38k
    bool const ifaceIsSet = cm::contains(propKeys, interfaceProperty);
615
4.38k
    PropertyType ifacePropContent = getTypedProperty<PropertyType>(
616
4.38k
      theTarget, interfaceProperty, genexInterpreter.get());
617
618
4.38k
    std::string reportEntry;
619
4.38k
    if (ifaceIsSet) {
620
871
      reportEntry += " * Target \"";
621
871
      reportEntry += theTarget->GetName();
622
871
      reportEntry += "\" property value \"";
623
871
      reportEntry += valueAsString<PropertyType>(ifacePropContent);
624
871
      reportEntry += "\" ";
625
871
    }
626
627
4.38k
    if (explicitlySet) {
628
0
      if (ifaceIsSet) {
629
0
        std::pair<bool, PropertyType> consistent =
630
0
          consistentProperty(propContent, ifacePropContent, t);
631
0
        report += reportEntry;
632
0
        report += compatibilityAgree(t, propContent != consistent.second);
633
0
        if (!consistent.first) {
634
0
          cmSystemTools::Error(
635
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
636
0
                     "\" does\nnot match the INTERFACE_", p,
637
0
                     " property requirement\nof dependency \"",
638
0
                     theTarget->GetName(), "\".\n"));
639
0
          break;
640
0
        }
641
0
        propContent = consistent.second;
642
0
        continue;
643
0
      }
644
      // Explicitly set on target and not set in iface. Can't disagree.
645
0
      continue;
646
0
    }
647
4.38k
    if (impliedByUse) {
648
0
      propContent = impliedValue<PropertyType>(propContent);
649
650
0
      if (ifaceIsSet) {
651
0
        std::pair<bool, PropertyType> consistent =
652
0
          consistentProperty(propContent, ifacePropContent, t);
653
0
        report += reportEntry;
654
0
        report += compatibilityAgree(t, propContent != consistent.second);
655
0
        if (!consistent.first) {
656
0
          cmSystemTools::Error(
657
0
            cmStrCat("Property ", p, " on target \"", tgt->GetName(),
658
0
                     "\" is\nimplied to be ", defaultValue,
659
0
                     " because it was used to determine the link libraries\n"
660
0
                     "already. The INTERFACE_",
661
0
                     p, " property on\ndependency \"", theTarget->GetName(),
662
0
                     "\" is in conflict.\n"));
663
0
          break;
664
0
        }
665
0
        propContent = consistent.second;
666
0
        continue;
667
0
      }
668
      // Implicitly set on target and not set in iface. Can't disagree.
669
0
      continue;
670
0
    }
671
4.38k
    if (ifaceIsSet) {
672
871
      if (propInitialized) {
673
0
        std::pair<bool, PropertyType> consistent =
674
0
          consistentProperty(propContent, ifacePropContent, t);
675
0
        report =
676
0
          cmStrCat(std::move(report), reportEntry,
677
0
                   compatibilityAgree(t, propContent != consistent.second));
678
0
        if (!consistent.first) {
679
0
          cmSystemTools::Error(cmStrCat(
680
0
            "The INTERFACE_", p, " property of \"", theTarget->GetName(),
681
0
            "\" does\nnot agree with the value of ", p,
682
0
            " already determined\nfor \"", tgt->GetName(), "\".\n"));
683
0
          break;
684
0
        }
685
0
        propContent = consistent.second;
686
0
        continue;
687
0
      }
688
871
      report = cmStrCat(std::move(report), reportEntry, "(Interface set)\n");
689
871
      propContent = ifacePropContent;
690
871
      propInitialized = true;
691
3.51k
    } else {
692
      // Not set. Nothing to agree on.
693
3.51k
      continue;
694
3.51k
    }
695
4.38k
  }
696
697
886
  tgt->ReportPropertyOrigin(p, valueAsString<PropertyType>(propContent),
698
886
                            report, compatibilityType(t));
699
886
  return propContent;
700
889
}
701
702
bool cmGeneratorTarget::GetLinkInterfaceDependentBoolProperty(
703
  std::string const& p, std::string const& config) const
704
47
{
705
47
  return checkInterfacePropertyCompatibility<bool>(this, p, config, "FALSE",
706
47
                                                   BoolType, nullptr);
707
47
}
708
709
std::string cmGeneratorTarget::GetLinkInterfaceDependentStringAsBoolProperty(
710
  std::string const& p, std::string const& config) const
711
0
{
712
0
  return checkInterfacePropertyCompatibility<std::string>(
713
0
    this, p, config, "FALSE", BoolType, nullptr);
714
0
}
715
716
char const* cmGeneratorTarget::GetLinkInterfaceDependentStringProperty(
717
  std::string const& p, std::string const& config) const
718
873
{
719
873
  return checkInterfacePropertyCompatibility<char const*>(
720
873
    this, p, config, "empty", StringType, nullptr);
721
873
}
722
723
char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMinProperty(
724
  std::string const& p, std::string const& config) const
725
0
{
726
0
  return checkInterfacePropertyCompatibility<char const*>(
727
0
    this, p, config, "empty", NumberMinType, nullptr);
728
0
}
729
730
char const* cmGeneratorTarget::GetLinkInterfaceDependentNumberMaxProperty(
731
  std::string const& p, std::string const& config) const
732
16
{
733
16
  return checkInterfacePropertyCompatibility<char const*>(
734
16
    this, p, config, "empty", NumberMaxType, nullptr);
735
16
}