@@ -986,6 +986,9 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
986986 auto project_root = project.root ();
987987 for (size_t i = 0 ; i < project.targets .size (); i++) {
988988 const auto &target = project.targets [i];
989+
990+ auto throw_target_error = [&target](const std::string &message) { throw std::runtime_error (" [target." + target.name + " ] " + message); };
991+
989992 const parser::Template *tmplate = nullptr ;
990993 std::unique_ptr<ConditionScope> tmplate_cs{};
991994
@@ -1089,7 +1092,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
10891092 auto sources = expand_cmake_paths (condition_sources, path, is_root_project);
10901093 if (sources.empty ()) {
10911094 auto source_key = condition.empty () ? " sources" : (condition + " .sources" );
1092- throw std::runtime_error (target. name + " " + source_key + " wildcard found 0 files" );
1095+ throw_target_error ( source_key + " wildcard found 0 files" );
10931096 }
10941097
10951098 // Make sure there are source files for the languages used by the project
@@ -1100,7 +1103,25 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
11001103 case parser::target_static:
11011104 case parser::target_object:
11021105 if (!contains_language_source (sources)) {
1103- throw std::runtime_error (" There were no source files linked within the target " + target.name );
1106+ std::string extensions;
1107+ for (const auto &language : project_extensions) {
1108+ if (!extensions.empty ()) {
1109+ extensions += " " ;
1110+ }
1111+ extensions += language;
1112+ }
1113+ throw_target_error (" No sources found with valid extensions (" + extensions + " )" );
1114+ }
1115+
1116+ // Make sure relative source files exist
1117+ for (const auto &source : sources) {
1118+ auto var_index = source.find (" ${" );
1119+ if (var_index != std::string::npos)
1120+ continue ;
1121+ const auto &source_path = fs::path (path) / source;
1122+ if (!fs::exists (source_path)) {
1123+ throw_target_error (" Source file does not exist " + source);
1124+ }
11041125 }
11051126 break ;
11061127 default :
@@ -1110,7 +1131,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
11101131 if (sources_with_set) {
11111132 // This is a sanity check to make sure the unconditional sources are first
11121133 if (!condition.empty ()) {
1113- throw std::runtime_error (" Unreachable code, make sure unconditional sources are first" );
1134+ throw_target_error (" Unreachable code, make sure unconditional sources are first" );
11141135 }
11151136 cmd (" set" )(sources_var, sources);
11161137 sources_with_set = false ;
@@ -1123,7 +1144,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
11231144
11241145 if (tmplate != nullptr ) {
11251146 if (target_type != parser::target_template) {
1126- throw std::runtime_error (" Unreachable code, unexpected target type for template" );
1147+ throw_target_error (" Unreachable code, unexpected target type for template" );
11271148 }
11281149 target_type = tmplate->outline .type ;
11291150 }
@@ -1171,7 +1192,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
11711192 target_scope = " PUBLIC" ;
11721193 break ;
11731194 default :
1174- throw std::runtime_error (" Unimplemented enum value" );
1195+ throw_target_error (" Unimplemented enum value" );
11751196 }
11761197
11771198 // Handle custom add commands from templates.
@@ -1252,7 +1273,7 @@ void generate_cmake(const char *path, const parser::Project *parent_project) {
12521273 for (const auto &propItr : properties) {
12531274 if (propItr.first == " MSVC_RUNTIME_LIBRARY" ) {
12541275 if (project_root->project_msvc_runtime == parser::msvc_last) {
1255- throw std::runtime_error (" You cannot set [target]. msvc-runtime without setting the root [project].msvc-runtime" );
1276+ throw_target_error (" You cannot set msvc-runtime without setting the root [project].msvc-runtime" );
12561277 }
12571278 }
12581279 }
0 commit comments