diff --git a/scripts/CMakeLists.txt b/scripts/CMakeLists.txt index 42dd014..92d78c8 100644 --- a/scripts/CMakeLists.txt +++ b/scripts/CMakeLists.txt @@ -455,27 +455,44 @@ function(dmod_create_module moduleName version moduleType) ) if(TODMM) - add_custom_command( - TARGET ${moduleName} POST_BUILD - # todmm --zip -o - # For a local manifest, base_url is the local packages directory path - COMMAND ${TODMM} "${DMOD_PACKAGES_DIR}" "${DMOD_PACKAGES_DIR}" --zip -o "${DMOD_LOCAL_MANIFEST_PATH}" - COMMENT "Generating local manifest for packages: ${DMOD_LOCAL_MANIFEST_PATH}" - ) + # Create a shared target (once per project) that regenerates the local + # manifest from ALL package zips after every module has been built. + # Using a dedicated target (rather than per-module POST_BUILD) guarantees + # that todmm runs only after ALL modules have created their zip archives, + # so the manifest is always complete when local .dmd files are generated. + if(NOT TARGET dmod_generate_manifest) + add_custom_target(dmod_generate_manifest ALL) + add_custom_command( + TARGET dmod_generate_manifest POST_BUILD + # todmm --zip -o + # For a local manifest, base_url is the local packages directory path + COMMAND ${TODMM} "${DMOD_PACKAGES_DIR}" "${DMOD_PACKAGES_DIR}" --zip -o "${DMOD_LOCAL_MANIFEST_PATH}" + COMMENT "Generating local manifest from all packages: ${DMOD_LOCAL_MANIFEST_PATH}" + ) + endif() + + # This module's zip must exist before the manifest is generated + add_dependencies(dmod_generate_manifest ${moduleName}) - # Generate -local.dmd using todmd with the local manifest + # Generate -local.dmd using todmd AFTER the complete manifest + # is ready (i.e., after all modules' zips have been collected by todmm). if(TODMD) set(LOCAL_DMD_OUTPUT "${DMOD_DMF_DIR}/${moduleName}-local.dmd") + + # A per-module ALL target that runs todmd once the manifest is complete + add_custom_target(${moduleName}_local_dmd ALL) + add_dependencies(${moduleName}_local_dmd dmod_generate_manifest) + get_target_property(VERSION_REQS_FILE ${moduleName} DMOD_VERSION_REQUIREMENTS_FILE) if(VERSION_REQS_FILE AND EXISTS "${VERSION_REQS_FILE}") add_custom_command( - TARGET ${moduleName} POST_BUILD + TARGET ${moduleName}_local_dmd POST_BUILD COMMAND ${TODMD} ${DMF_OUTPUT} ${DMD_OUTPUT} -r ${VERSION_REQS_FILE} --local-manifest "${DMOD_LOCAL_MANIFEST_PATH}" COMMENT "Generating local dependencies file: ${LOCAL_DMD_OUTPUT}" ) else() add_custom_command( - TARGET ${moduleName} POST_BUILD + TARGET ${moduleName}_local_dmd POST_BUILD COMMAND ${TODMD} ${DMF_OUTPUT} ${DMD_OUTPUT} --local-manifest "${DMOD_LOCAL_MANIFEST_PATH}" COMMENT "Generating local dependencies file: ${LOCAL_DMD_OUTPUT}" ) diff --git a/tests/integration/test_todmd.sh b/tests/integration/test_todmd.sh index a833773..d32e375 100755 --- a/tests/integration/test_todmd.sh +++ b/tests/integration/test_todmd.sh @@ -245,7 +245,7 @@ EOF fi echo "" - echo "Test 11: Verify local .dmd uses \$from for locally available deps" + echo "Test 11: Verify local .dmd uses \$from for locally available deps and lists non-local deps without \$from" if [ -n "$DMF_FILE" ] && [ -f "$DMF_FILE" ]; then # Get the list of dependencies from the regular .dmd @@ -271,6 +271,22 @@ EOF echo "✗ Expected \$from directive for ${FIRST_DEP} in local .dmd" exit 1 fi + + # Non-local deps (all except FIRST_DEP) must appear WITHOUT $from in the local .dmd + OTHER_DEPS=$(echo "$DEPS" | tail -n +2) + for dep in $OTHER_DEPS; do + if ! grep -v '^#' test_local_dep-local.dmd | grep -q "^${dep}"; then + echo "✗ Non-local dependency '${dep}' is missing from local .dmd" + exit 1 + fi + if grep -v '^#' test_local_dep-local.dmd | grep "^${dep}" | grep -q "\$from"; then + echo "✗ Non-local dependency '${dep}' should not have \$from in local .dmd" + exit 1 + fi + done + if [ -n "$OTHER_DEPS" ]; then + echo "✓ Non-local dependencies appear without \$from in local .dmd" + fi else echo "✗ Local .dmd file test_local_dep-local.dmd was not created" exit 1 diff --git a/tools/system/todmd/main.c b/tools/system/todmd/main.c index 3fb9453..483c4dc 100644 --- a/tools/system/todmd/main.c +++ b/tools/system/todmd/main.c @@ -228,8 +228,8 @@ void PrintHelp( const char* AppName ) printf(" --from = Per-module manifest: adds inline $from for the named module\n"); printf(" Option can be repeated to set manifests for multiple modules\n"); printf(" --local-manifest Local manifest (.dmm) file; generates a companion\n"); - printf(" -local.dmd where dependencies present in the manifest\n"); - printf(" get an inline $from directive\n"); + printf(" -local.dmd listing only dependencies present in\n"); + printf(" the manifest, each with an inline $from directive\n"); printf("\nArguments:\n"); printf(" path/to/file.dmf Path to the DMF module file\n"); printf(" [output.dmd] (optional) Output .dmd file path (default: module_name.dmd)\n"); @@ -247,9 +247,10 @@ void PrintHelp( const char* AppName ) printf(" only for that specific module using the $from syntax.\n"); printf("\n"); printf(" If --local-manifest is provided, a companion -local.dmd file is\n"); - printf(" generated alongside the regular .dmd. In this file, dependencies that are\n"); - printf(" present in the local manifest receive an inline $from directive\n"); - printf(" so they can be resolved from the local build.\n"); + printf(" generated alongside the regular .dmd. All non-system dependencies are listed:\n"); + printf(" those present in the local manifest get an inline $from directive\n"); + printf(" so they are resolved from the local build; all other dependencies are listed\n"); + printf(" without $from so they are fetched from the default remote repository.\n"); printf("\nExamples:\n"); printf(" %s myapp.dmf # Creates myapp.dmd\n", AppName); printf(" %s myapp.dmf dependencies.dmd # Creates dependencies.dmd\n", AppName); @@ -676,7 +677,9 @@ int main( int argc, char *argv[] ) } } - // Use local manifest as $from source if this module is available locally + // Use local manifest as $from source if this module is available locally; + // non-local modules are still listed (without $from) so they are fetched + // from the default remote repository. bool isLocal = IsModuleInLocalManifest( localManifestModules, localManifestModuleCount, reqModule->Name ); if( versionToUse != NULL )