@@ -1216,6 +1216,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
12161216 }
12171217 }
12181218
1219+ auto resolved_target_type = target.type ;
1220+ if (tmplate != nullptr ) {
1221+ if (resolved_target_type != parser::target_template) {
1222+ throw_target_error (" Unreachable code, unexpected target type for template" );
1223+ }
1224+ resolved_target_type = tmplate->outline .type ;
1225+ }
1226+
12191227 ConditionScope cs (gen, target.condition );
12201228
12211229 // Detect if there is cmake included before/after the target
@@ -1317,6 +1325,31 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13171325 }
13181326 custom_commands.insert (custom_commands.end (), target.custom_commands .begin (), target.custom_commands .end ());
13191327
1328+ auto normalize_generated_output_source = [](const std::string &output) {
1329+ auto starts_with = [](const std::string &value, const std::string &prefix) {
1330+ return value.rfind (prefix, 0 ) == 0 ;
1331+ };
1332+ if (fs::path (output).is_absolute ()) {
1333+ return output;
1334+ }
1335+ if (starts_with (output, " ${CMAKE_CURRENT_BINARY_DIR}" ) || starts_with (output, " ${CMAKE_BINARY_DIR}" ) ||
1336+ starts_with (output, " ${PROJECT_BINARY_DIR}" ) || starts_with (output, " ${CMAKE_CURRENT_SOURCE_DIR}" ) ||
1337+ starts_with (output, " ${CMAKE_SOURCE_DIR}" ) || starts_with (output, " ${PROJECT_SOURCE_DIR}" ) ||
1338+ starts_with (output, " ${CMAKE_CURRENT_LIST_DIR}" ) || starts_with (output, " $ENV{" ) || starts_with (output, " $CACHE{" ) ||
1339+ starts_with (output, " ${" )) {
1340+ return output;
1341+ }
1342+ return " ${CMAKE_CURRENT_BINARY_DIR}/" + output;
1343+ };
1344+
1345+ parser::Condition<tsl::ordered_set<std::string>> mcustom_target_depends;
1346+ if (resolved_target_type == parser::target_custom) {
1347+ auto &unconditional_depends = mcustom_target_depends[" " ];
1348+ for (const auto &dep : custom_target.depends ) {
1349+ unconditional_depends.insert (dep);
1350+ }
1351+ }
1352+
13201353 // Merge the sources from the template and the target. The sources
13211354 // without condition need to be processed first
13221355 parser::Condition<tsl::ordered_set<std::string>> msources;
@@ -1341,12 +1374,15 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13411374 }
13421375 auto &condition_sources = msources[custom_command.condition ];
13431376 for (const auto &output : custom_command.outputs ) {
1344- condition_sources.insert (output);
1377+ condition_sources.insert (normalize_generated_output_source (output));
1378+ if (resolved_target_type == parser::target_custom) {
1379+ mcustom_target_depends[custom_command.condition ].insert (output);
1380+ }
13451381 }
13461382 }
13471383
13481384 // Improve IDE support
1349- if (target. type != parser::target_interface) {
1385+ if (resolved_target_type != parser::target_interface) {
13501386 msources[" " ].insert (" cmake.toml" );
13511387 }
13521388
@@ -1380,7 +1416,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13801416 }
13811417
13821418 // Make sure there are source files for the languages used by the project
1383- switch (target. type ) {
1419+ switch (resolved_target_type ) {
13841420 case parser::target_executable:
13851421 case parser::target_library:
13861422 case parser::target_shared:
@@ -1424,14 +1460,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
14241460 }
14251461 });
14261462
1427- auto target_type = target.type ;
1428-
1429- if (tmplate != nullptr ) {
1430- if (target_type != parser::target_template) {
1431- throw_target_error (" Unreachable code, unexpected target type for template" );
1432- }
1433- target_type = tmplate->outline .type ;
1434- }
1463+ auto target_type = resolved_target_type;
14351464
14361465 std::string add_command;
14371466 std::string target_type_string;
@@ -1478,6 +1507,39 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
14781507 throw_target_error (" Unimplemented enum value" );
14791508 }
14801509
1510+ auto has_custom_target_depends = false ;
1511+ auto custom_target_depends_var = target.name + " _DEPENDS" ;
1512+ auto custom_target_depends_with_set = true ;
1513+ if (is_custom_target) {
1514+ for (const auto &itr : mcustom_target_depends) {
1515+ if (!itr.second .empty ()) {
1516+ has_custom_target_depends = true ;
1517+ break ;
1518+ }
1519+ }
1520+ if (has_custom_target_depends && mcustom_target_depends[" " ].empty ()) {
1521+ custom_target_depends_with_set = false ;
1522+ cmd (" set" )(custom_target_depends_var, RawArg (" \"\" " )).endl ();
1523+ }
1524+ gen.handle_condition (mcustom_target_depends, [&](const std::string &condition, const tsl::ordered_set<std::string> &depend_set) {
1525+ std::vector<std::string> depends;
1526+ depends.reserve (depend_set.size ());
1527+ for (const auto &depend : depend_set) {
1528+ depends.push_back (depend);
1529+ }
1530+
1531+ if (custom_target_depends_with_set) {
1532+ if (!condition.empty ()) {
1533+ throw_target_error (" Unreachable code, make sure unconditional depends are first" );
1534+ }
1535+ cmd (" set" )(custom_target_depends_var, depends);
1536+ custom_target_depends_with_set = false ;
1537+ } else {
1538+ cmd (" list" )(" APPEND" , custom_target_depends_var, depends);
1539+ }
1540+ });
1541+ }
1542+
14811543 auto append_keyword = [](std::vector<RawArg> &args, const std::string &keyword) {
14821544 args.emplace_back (keyword);
14831545 };
@@ -1616,9 +1678,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
16161678 append_keyword (args, " ALL" );
16171679 }
16181680 append_commands (args, custom_target.commands );
1619- if (!custom_target. depends . empty () ) {
1681+ if (has_custom_target_depends ) {
16201682 append_keyword (args, " DEPENDS" );
1621- append_values (args, custom_target. depends );
1683+ append_value (args, " ${ " + custom_target_depends_var + " } " );
16221684 }
16231685 if (!custom_target.byproducts .empty ()) {
16241686 append_keyword (args, " BYPRODUCTS" );
0 commit comments