@@ -1222,6 +1222,14 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
12221222 }
12231223 }
12241224
1225+ auto resolved_target_type = target.type ;
1226+ if (tmplate != nullptr ) {
1227+ if (resolved_target_type != parser::target_template) {
1228+ throw_target_error (" Unreachable code, unexpected target type for template" );
1229+ }
1230+ resolved_target_type = tmplate->outline .type ;
1231+ }
1232+
12251233 ConditionScope cs (gen, target.condition );
12261234
12271235 // Detect if there is cmake included before/after the target
@@ -1323,6 +1331,31 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13231331 }
13241332 custom_commands.insert (custom_commands.end (), target.custom_commands .begin (), target.custom_commands .end ());
13251333
1334+ auto normalize_generated_output_source = [](const std::string &output) {
1335+ auto starts_with = [](const std::string &value, const std::string &prefix) {
1336+ return value.rfind (prefix, 0 ) == 0 ;
1337+ };
1338+ if (fs::path (output).is_absolute ()) {
1339+ return output;
1340+ }
1341+ if (starts_with (output, " ${CMAKE_CURRENT_BINARY_DIR}" ) || starts_with (output, " ${CMAKE_BINARY_DIR}" ) ||
1342+ starts_with (output, " ${PROJECT_BINARY_DIR}" ) || starts_with (output, " ${CMAKE_CURRENT_SOURCE_DIR}" ) ||
1343+ starts_with (output, " ${CMAKE_SOURCE_DIR}" ) || starts_with (output, " ${PROJECT_SOURCE_DIR}" ) ||
1344+ starts_with (output, " ${CMAKE_CURRENT_LIST_DIR}" ) || starts_with (output, " $ENV{" ) || starts_with (output, " $CACHE{" ) ||
1345+ starts_with (output, " ${" )) {
1346+ return output;
1347+ }
1348+ return " ${CMAKE_CURRENT_BINARY_DIR}/" + output;
1349+ };
1350+
1351+ parser::Condition<tsl::ordered_set<std::string>> mcustom_target_depends;
1352+ if (resolved_target_type == parser::target_custom) {
1353+ auto &unconditional_depends = mcustom_target_depends[" " ];
1354+ for (const auto &dep : custom_target.depends ) {
1355+ unconditional_depends.insert (dep);
1356+ }
1357+ }
1358+
13261359 // Merge the sources from the template and the target. The sources
13271360 // without condition need to be processed first
13281361 parser::Condition<tsl::ordered_set<std::string>> msources;
@@ -1347,12 +1380,15 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13471380 }
13481381 auto &condition_sources = msources[custom_command.condition ];
13491382 for (const auto &output : custom_command.outputs ) {
1350- condition_sources.insert (output);
1383+ condition_sources.insert (normalize_generated_output_source (output));
1384+ if (resolved_target_type == parser::target_custom) {
1385+ mcustom_target_depends[custom_command.condition ].insert (output);
1386+ }
13511387 }
13521388 }
13531389
13541390 // Improve IDE support
1355- if (target. type != parser::target_interface) {
1391+ if (resolved_target_type != parser::target_interface) {
13561392 msources[" " ].insert (" cmake.toml" );
13571393 }
13581394
@@ -1386,7 +1422,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
13861422 }
13871423
13881424 // Make sure there are source files for the languages used by the project
1389- switch (target. type ) {
1425+ switch (resolved_target_type ) {
13901426 case parser::target_executable:
13911427 case parser::target_library:
13921428 case parser::target_shared:
@@ -1430,14 +1466,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
14301466 }
14311467 });
14321468
1433- auto target_type = target.type ;
1434-
1435- if (tmplate != nullptr ) {
1436- if (target_type != parser::target_template) {
1437- throw_target_error (" Unreachable code, unexpected target type for template" );
1438- }
1439- target_type = tmplate->outline .type ;
1440- }
1469+ auto target_type = resolved_target_type;
14411470
14421471 std::string add_command;
14431472 std::string target_type_string;
@@ -1484,6 +1513,39 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
14841513 throw_target_error (" Unimplemented enum value" );
14851514 }
14861515
1516+ auto has_custom_target_depends = false ;
1517+ auto custom_target_depends_var = target.name + " _DEPENDS" ;
1518+ auto custom_target_depends_with_set = true ;
1519+ if (is_custom_target) {
1520+ for (const auto &itr : mcustom_target_depends) {
1521+ if (!itr.second .empty ()) {
1522+ has_custom_target_depends = true ;
1523+ break ;
1524+ }
1525+ }
1526+ if (has_custom_target_depends && mcustom_target_depends[" " ].empty ()) {
1527+ custom_target_depends_with_set = false ;
1528+ cmd (" set" )(custom_target_depends_var, RawArg (" \"\" " )).endl ();
1529+ }
1530+ gen.handle_condition (mcustom_target_depends, [&](const std::string &condition, const tsl::ordered_set<std::string> &depend_set) {
1531+ std::vector<std::string> depends;
1532+ depends.reserve (depend_set.size ());
1533+ for (const auto &depend : depend_set) {
1534+ depends.push_back (depend);
1535+ }
1536+
1537+ if (custom_target_depends_with_set) {
1538+ if (!condition.empty ()) {
1539+ throw_target_error (" Unreachable code, make sure unconditional depends are first" );
1540+ }
1541+ cmd (" set" )(custom_target_depends_var, depends);
1542+ custom_target_depends_with_set = false ;
1543+ } else {
1544+ cmd (" list" )(" APPEND" , custom_target_depends_var, depends);
1545+ }
1546+ });
1547+ }
1548+
14871549 auto append_keyword = [](std::vector<RawArg> &args, const std::string &keyword) {
14881550 args.emplace_back (keyword);
14891551 };
@@ -1622,9 +1684,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
16221684 append_keyword (args, " ALL" );
16231685 }
16241686 append_commands (args, custom_target.commands );
1625- if (!custom_target. depends . empty () ) {
1687+ if (has_custom_target_depends ) {
16261688 append_keyword (args, " DEPENDS" );
1627- append_values (args, custom_target. depends );
1689+ append_value (args, " ${ " + custom_target_depends_var + " } " );
16281690 }
16291691 if (!custom_target.byproducts .empty ()) {
16301692 append_keyword (args, " BYPRODUCTS" );
0 commit comments