Coverage Report

Created: 2026-07-14 07:09

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