diff --git a/.github/workflows/pr_info_intro.yml b/.github/workflows/pr_info_intro.yml new file mode 100644 index 0000000..89db541 --- /dev/null +++ b/.github/workflows/pr_info_intro.yml @@ -0,0 +1,25 @@ +name: PR Info (pre-comment) + +on: + # NOTE: high probability for security vulnerabilities if doing ANYTHING in + # this file other than commenting something! + pull_request_target: + branches: + - master + - stable + +jobs: + intro_comment: + name: Make intro comment + runs-on: ubuntu-20.04 + steps: + - name: 'Prepare sticky comment' + # commit of v2.5.0 + # same one used again at the bottom of the file to update the comment. + uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd + with: + message: | + Thanks for your Pull Request and making D better! + + This comment will automatically be updated to summarize some statistics in a few minutes. + only_create: true diff --git a/.github/workflows/pr_info_post.yml b/.github/workflows/pr_info_post.yml new file mode 100644 index 0000000..c3a0914 --- /dev/null +++ b/.github/workflows/pr_info_post.yml @@ -0,0 +1,49 @@ +name: PR Info (comment) + +on: + workflow_run: + workflows: ["PR Info"] + types: + - completed + +jobs: + comment: + name: PR Info + runs-on: ubuntu-20.04 + if: > + github.event.workflow_run.event == 'pull_request' && + github.event.workflow_run.conclusion == 'success' + steps: + # from https://securitylab.github.com/research/github-actions-preventing-pwn-requests/ + - name: 'Download artifact' + uses: actions/github-script@v3.1.0 + with: + script: | + var artifacts = await github.actions.listWorkflowRunArtifacts({ + owner: context.repo.owner, + repo: context.repo.repo, + run_id: ${{github.event.workflow_run.id }}, + }); + var matchArtifact = artifacts.data.artifacts.filter((artifact) => { + return artifact.name == "pr" + })[0]; + var download = await github.actions.downloadArtifact({ + owner: context.repo.owner, + repo: context.repo.repo, + artifact_id: matchArtifact.id, + archive_format: 'zip', + }); + var fs = require('fs'); + fs.writeFileSync('${{github.workspace}}/pr.zip', Buffer.from(download.data)); + - run: unzip pr.zip + + - name: Set variable + run: | + PR_ID=$(cat ./NR) + echo "PR_ID=$PR_ID" >> $GITHUB_ENV + + - name: Update GitHub comment + uses: marocchino/sticky-pull-request-comment@3d60a5b2dae89d44e0c6ddc69dd7536aec2071cd + with: + path: ./comment.txt + number: ${{ env.PR_ID }} diff --git a/.github/workflows/pr_info_untrusted.yml b/.github/workflows/pr_info_untrusted.yml new file mode 100644 index 0000000..c3416e5 --- /dev/null +++ b/.github/workflows/pr_info_untrusted.yml @@ -0,0 +1,68 @@ +name: PR Info + +# This workflow builds the whole project once and: +# - comments build deprecations/warnings (highlighting new ones since last tested PR) + +on: + pull_request: + branches: + - master + - stable + +jobs: + pr_info: + name: PR Info + runs-on: ubuntu-20.04 + steps: + # we first create a comment thanking the user in pr_info_intro.yml + # (separate step due to needing GITHUB_TOKEN access) + + - name: '[Linux] Install dependencies' + if: runner.os == 'Linux' + run: | + sudo apt-get update && sudo apt-get install -y libcurl4-openssl-dev netcat + + # Compiler to test with + - name: Prepare compiler + uses: dlang-community/setup-dlang@v1 + with: + compiler: ldc-latest + + - name: Checkout + uses: actions/checkout@v3 + with: + fetch-depth: 0 + + - name: Checkout old stuff, with new comment script + run: | + git checkout ${{ github.base_ref }} + git checkout ${{ github.sha }} -- ./scripts/ci/summary_comment.sh ./scripts/ci/summary_comment_diff.sh + + # first dump old info + + - name: Check pre-PR status + run: ./scripts/ci/summary_comment.sh | tee ../OLD_OUTPUT.txt + + - name: Checkout PR target + run: | + git checkout ${{ github.sha }} + git clean -fd + git reset --hard + + - name: Evaluate PR + run: ./scripts/ci/summary_comment.sh | tee ../NEW_OUTPUT.txt + + - name: Generate comment + run: ./scripts/ci/summary_comment_diff.sh ../OLD_OUTPUT.txt ../NEW_OUTPUT.txt | tee comment.txt + + - name: Prepare comment for upload + run: | + mkdir -p ./pr + mv comment.txt pr + echo ${{ github.event.number }} > ./pr/NR + + - name: upload comment to high-trust action making the comment + uses: actions/upload-artifact@v2 + with: + name: pr + path: pr/ diff --git a/changelog/collect_c_source_and_headers_for_ImportC.dd b/changelog/collect_c_source_and_headers_for_ImportC.dd new file mode 100644 index 0000000..59bc29d --- /dev/null +++ b/changelog/collect_c_source_and_headers_for_ImportC.dd @@ -0,0 +1,9 @@ +Add new properties 'cSourcePaths' and 'cImportPaths' to SDL/JSON + +`cSourcePaths` passes the C source files in all specified directories to the compiler. +All C sources found in the given directories for 'cImportPaths' are passed to the D compiler. +This ensures backward compatible behaviour for projects that stored C sources aside of D source file, while porting them to D. + +The second keyword 'cImportPaths' will add additional search paths for C headers. These directories are passed to the D compilers +as addition include paths. The feature might need additional tweaking, because the include paths are currently joint with the +D import paths. This might change in future to support independant search paths for C to be passed to the D compilers. diff --git a/changelog/hierarchy.dd b/changelog/hierarchy.dd new file mode 100644 index 0000000..c087297 --- /dev/null +++ b/changelog/hierarchy.dd @@ -0,0 +1,16 @@ +The way packages are stored internally has changed + +Previous versions of dub stored packages in the following format: +`$CACHE_PATH/$PACKAGE_NAME-$PACKAGE_VERSION/$PACKAGE_NAME/` +Starting from this version, the format will be: +`$CACHE_PATH/$PACKAGE_NAME/$PACKAGE_VERSION/$PACKAGE_NAME`. + +Introducing a new level will help users quickly list what packages +they actually have installed, and reduce visibility of packages that +might update frequently. It will render various commands (e.g. `du`) +more useful, pave the way for a package GC function, and make manual +browsing easier. + +More importantly, it will allow future version of dub to infer the +version from the path to the package, removing the need to read (or edit) +the recipe file on every dub invocation. diff --git a/dub.selections.json b/dub.selections.json index 28ff597..c675e35 100644 --- a/dub.selections.json +++ b/dub.selections.json @@ -4,16 +4,16 @@ "botan": "1.12.19", "botan-math": "1.0.3", "diet-ng": "1.8.1", - "eventcore": "0.9.20", + "eventcore": "0.9.23", "libasync": "0.8.6", "libev": "5.0.0+4.04", "libevent": "2.0.2+2.0.16", - "memutils": "1.0.4", + "memutils": "1.0.9", "mir-linux-kernel": "1.0.1", - "openssl": "3.2.2", + "openssl": "3.3.0", "stdx-allocator": "2.77.5", "taggedalgebraic": "0.11.22", - "vibe-core": "1.22.4", + "vibe-core": "1.23.0", "vibe-d": "0.9.5" } } diff --git a/scripts/ci/summary_comment.sh b/scripts/ci/summary_comment.sh new file mode 100755 index 0000000..fb1f2bf --- /dev/null +++ b/scripts/ci/summary_comment.sh @@ -0,0 +1,28 @@ +#!/usr/bin/env bash + +set -u + +# Output from this script is piped to a file by CI, being run from before a +# change has been made and after a change has been made. Then both outputs are +# compared using summary_comment_diff.sh + +# cd to git folder, just in case this is manually run: +ROOT_DIR="$( cd "$(dirname "${BASH_SOURCE[0]}")/../../" && pwd )" +cd ${ROOT_DIR} + +dub --version +ldc2 --version + +# fetch missing packages before timing +dub upgrade --missing-only + +start=`date +%s` +dub build --build=release --force 2>&1 || echo "BUILD FAILED" +end=`date +%s` +build_time=$( echo "$end - $start" | bc -l ) + +strip bin/dub + +echo "STAT:statistics (-before, +after)" +echo "STAT:executable size=$(wc -c bin/dub)" +echo "STAT:rough build time=${build_time}s" diff --git a/scripts/ci/summary_comment_diff.sh b/scripts/ci/summary_comment_diff.sh new file mode 100755 index 0000000..4831abe --- /dev/null +++ b/scripts/ci/summary_comment_diff.sh @@ -0,0 +1,111 @@ +#!/usr/bin/env bash + +set -u + +EMPTY=1 + +ADDED=$(diff --new-line-format='%L' --old-line-format='' --unchanged-line-format='' "$1" "$2") +REMOVED=$(diff --new-line-format='' --old-line-format='%L' --unchanged-line-format='' "$1" "$2") +TOTAL=$(cat "$2") + +STATS_OLD=$(grep -E '^STAT:' "$1" | sed -E 's/^STAT://') +STATS_NEW=$(grep -E '^STAT:' "$2" | sed -E 's/^STAT://') + +STATS_DIFFED=$(diff --new-line-format='+%L' --old-line-format='-%L' --unchanged-line-format=' %L' <(echo "$STATS_OLD") <(echo "$STATS_NEW")) + +ADDED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$ADDED") +REMOVED_DEPRECATIONS=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$REMOVED") +ADDED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$ADDED") +REMOVED_WARNINGS=$(grep -Pi '\b(warn|warning)\b' <<< "$REMOVED") + +DEPRECATION_COUNT=$(grep -Pi '\b(deprecation|deprecated)\b' <<< "$TOTAL" | wc -l) +WARNING_COUNT=$(grep -Pi '\b(warn|warning)\b' <<< "$TOTAL" | wc -l) + +if [ -z "$ADDED_DEPRECATIONS" ]; then + # no new deprecations + true +else + echo "⚠️ This PR introduces new deprecations:" + echo + echo '```' + echo "$ADDED_DEPRECATIONS" + echo '```' + echo + EMPTY=0 +fi + +if [ -z "$ADDED_WARNINGS" ]; then + # no new deprecations + true +else + echo "⚠️ This PR introduces new warnings:" + echo + echo '```' + echo "$ADDED_WARNINGS" + echo '```' + echo + EMPTY=0 +fi + +if grep "BUILD FAILED" <<< "$TOTAL"; then + echo '❌ Basic `dub build` failed! Please check your changes again.' + echo +else + if [ -z "$REMOVED_DEPRECATIONS" ]; then + # no removed deprecations + true + else + echo "✅ This PR fixes following deprecations:" + echo + echo '```' + echo "$REMOVED_DEPRECATIONS" + echo '```' + echo + EMPTY=0 + fi + + if [ -z "$REMOVED_WARNINGS" ]; then + # no removed warnings + true + else + echo "✅ This PR fixes following warnings:" + echo + echo '```' + echo "$REMOVED_WARNINGS" + echo '```' + echo + EMPTY=0 + fi + + if [ $EMPTY == 1 ]; then + echo "✅ PR OK, no changes in deprecations or warnings" + echo + fi + + echo "Total deprecations: $DEPRECATION_COUNT" + echo + echo "Total warnings: $WARNING_COUNT" + echo +fi + +if [ -z "$STATS_DIFFED" ]; then + # no statistics? + true +else + echo "Build statistics:" + echo + echo '```diff' + echo "$STATS_DIFFED" + echo '```' + echo +fi + +echo '
' +echo +echo 'Full build output' +echo +echo '```' +echo "$TOTAL" +echo '```' +echo +echo '
' diff --git a/source/dub/compilers/buildsettings.d b/source/dub/compilers/buildsettings.d index c7b06b0..9d5652c 100644 --- a/source/dub/compilers/buildsettings.d +++ b/source/dub/compilers/buildsettings.d @@ -41,6 +41,7 @@ string[] versionFilters; string[] debugVersionFilters; string[] importPaths; + string[] cImportPaths; string[] stringImportPaths; string[] importFiles; string[] stringImportFiles; @@ -81,6 +82,7 @@ assert(ret.targetType == targetType); assert(ret.targetName == targetName); assert(ret.importPaths == importPaths); + assert(ret.cImportPaths == cImportPaths); return ret; } @@ -105,6 +107,7 @@ addVersionFilters(bs.versionFilters); addDebugVersionFilters(bs.debugVersionFilters); addImportPaths(bs.importPaths); + addCImportPaths(bs.cImportPaths); addStringImportPaths(bs.stringImportPaths); addImportFiles(bs.importFiles); addStringImportFiles(bs.stringImportFiles); @@ -145,6 +148,7 @@ void addVersionFilters(in string[] value...) { add(versionFilters, value); } void addDebugVersionFilters(in string[] value...) { add(debugVersionFilters, value); } void addImportPaths(in string[] value...) { add(importPaths, value); } + void addCImportPaths(in string[] value...) { add(cImportPaths, value); } void addStringImportPaths(in string[] value...) { add(stringImportPaths, value); } void prependStringImportPaths(in string[] value...) { prepend(stringImportPaths, value); } void addImportFiles(in string[] value...) { add(importFiles, value); } @@ -329,12 +333,13 @@ versions = 1<<5, debugVersions = 1<<6, importPaths = 1<<7, - stringImportPaths = 1<<8, - options = 1<<9, + cImportPaths = 1<<8, + stringImportPaths = 1<<9, + options = 1<<10, none = 0, commandLine = dflags|copyFiles, commandLineSeparate = commandLine|lflags, - all = dflags|lflags|libs|sourceFiles|copyFiles|versions|debugVersions|importPaths|stringImportPaths|options, + all = dflags|lflags|libs|sourceFiles|copyFiles|versions|debugVersions|importPaths|cImportPaths|stringImportPaths|options, noOptions = all & ~options } diff --git a/source/dub/compilers/dmd.d b/source/dub/compilers/dmd.d index 166f6b5..78fd9d4 100644 --- a/source/dub/compilers/dmd.d +++ b/source/dub/compilers/dmd.d @@ -251,6 +251,11 @@ settings.importPaths = null; } + if (!(fields & BuildSetting.cImportPaths)) { + settings.addDFlags(settings.cImportPaths.map!(s => "-I"~s)().array()); + settings.cImportPaths = null; + } + if (!(fields & BuildSetting.stringImportPaths)) { settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); settings.stringImportPaths = null; diff --git a/source/dub/compilers/gdc.d b/source/dub/compilers/gdc.d index d7a8e4c..0d34446 100644 --- a/source/dub/compilers/gdc.d +++ b/source/dub/compilers/gdc.d @@ -110,6 +110,11 @@ settings.importPaths = null; } + if (!(fields & BuildSetting.cImportPaths)) { + settings.addDFlags(settings.cImportPaths.map!(s => "-I"~s)().array()); + settings.cImportPaths = null; + } + if (!(fields & BuildSetting.stringImportPaths)) { settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); settings.stringImportPaths = null; diff --git a/source/dub/compilers/ldc.d b/source/dub/compilers/ldc.d index 6b8f545..3cb90e5 100644 --- a/source/dub/compilers/ldc.d +++ b/source/dub/compilers/ldc.d @@ -131,6 +131,11 @@ settings.importPaths = null; } + if (!(fields & BuildSetting.cImportPaths)) { + settings.addDFlags(settings.cImportPaths.map!(s => "-I"~s)().array()); + settings.cImportPaths = null; + } + if (!(fields & BuildSetting.stringImportPaths)) { settings.addDFlags(settings.stringImportPaths.map!(s => "-J"~s)().array()); settings.stringImportPaths = null; diff --git a/source/dub/description.d b/source/dub/description.d index bf580bd..fb2dc8f 100644 --- a/source/dub/description.d +++ b/source/dub/description.d @@ -90,6 +90,7 @@ string[] versions; /// D version identifiers to set string[] debugVersions; /// D debug version identifiers to set string[] importPaths; + string[] cImportPaths; string[] stringImportPaths; string[] preGenerateCommands; /// Commands executed before creating the description, with variables not substituted. string[] postGenerateCommands; /// Commands executed after creating the description, with variables not substituted. diff --git a/source/dub/dub.d b/source/dub/dub.d index 64a1426..28ada24 100644 --- a/source/dub/dub.d +++ b/source/dub/dub.d @@ -524,10 +524,14 @@ auto recipe = parsePackageRecipe(recipe_content, recipe_filename, null, recipe_default_package_name); enforce(recipe.buildSettings.sourceFiles.length == 0, "Single-file packages are not allowed to specify source files."); enforce(recipe.buildSettings.sourcePaths.length == 0, "Single-file packages are not allowed to specify source paths."); + enforce(recipe.buildSettings.cSourcePaths.length == 0, "Single-file packages are not allowed to specify C source paths."); enforce(recipe.buildSettings.importPaths.length == 0, "Single-file packages are not allowed to specify import paths."); + enforce(recipe.buildSettings.cImportPaths.length == 0, "Single-file packages are not allowed to specify C import paths."); recipe.buildSettings.sourceFiles[""] = [path.toNativeString()]; recipe.buildSettings.sourcePaths[""] = []; + recipe.buildSettings.cSourcePaths[""] = []; recipe.buildSettings.importPaths[""] = []; + recipe.buildSettings.cImportPaths[""] = []; recipe.buildSettings.mainSourceFile = path.toNativeString(); if (recipe.buildSettings.targetType == TargetType.autodetect) recipe.buildSettings.targetType = TargetType.executable; @@ -747,6 +751,9 @@ foreach (importPath; buildSettings.importPaths) { settings.runArgs ~= ["-I", buildNormalizedPath(dependencyPackage.path.toNativeString(), importPath.idup)]; } + foreach (cimportPath; buildSettings.cImportPaths) { + settings.runArgs ~= ["-I", buildNormalizedPath(dependencyPackage.path.toNativeString(), cimportPath.idup)]; + } } string configFilePath = buildPath(m_project.rootPackage.path.toNativeString(), "dscanner.ini"); diff --git a/source/dub/generators/build.d b/source/dub/generators/build.d index 6ea65b5..8583eab 100644 --- a/source/dub/generators/build.d +++ b/source/dub/generators/build.d @@ -214,6 +214,7 @@ string makeRelative(string path) { return shrinkPath(NativePath(path), cwd); } foreach (ref f; buildsettings.sourceFiles) f = makeRelative(f); foreach (ref p; buildsettings.importPaths) p = makeRelative(p); + foreach (ref p; buildsettings.cImportPaths) p = makeRelative(p); foreach (ref p; buildsettings.stringImportPaths) p = makeRelative(p); // perform the actual build @@ -378,6 +379,7 @@ } buildsettings.targetPath = makeRelative(buildsettings.targetPath); foreach (ref p; buildsettings.importPaths) p = makeRelative(p); + foreach (ref p; buildsettings.cImportPaths) p = makeRelative(p); foreach (ref p; buildsettings.stringImportPaths) p = makeRelative(p); bool is_temp_target = false; @@ -683,6 +685,7 @@ buildsettings.lflags, buildsettings.stringImportPaths, buildsettings.importPaths, + buildsettings.cImportPaths, settings.platform.architecture, [ (cast(uint)(buildsettings.options & ~BuildOption.color)).to!string, // exclude color option from id diff --git a/source/dub/generators/cmake.d b/source/dub/generators/cmake.d index b87a368..5c679fb 100644 --- a/source/dub/generators/cmake.d +++ b/source/dub/generators/cmake.d @@ -84,6 +84,9 @@ foreach(directory; info.buildSettings.importPaths) script.put("include_directories(%s)\n".format(directory.sanitizeSlashes)); + foreach(directory; info.buildSettings.cImportPaths) + script.put("c_include_directories(%s)\n".format(directory.sanitizeSlashes)); + if(addTarget) { script.put("add_%s(%s %s\n".format(targetType, name, libType)); diff --git a/source/dub/generators/generator.d b/source/dub/generators/generator.d index 72282f7..8ff77d0 100644 --- a/source/dub/generators/generator.d +++ b/source/dub/generators/generator.d @@ -740,6 +740,7 @@ parent.addVersionFilters(child.versionFilters); parent.addDebugVersionFilters(child.debugVersionFilters); parent.addImportPaths(child.importPaths); + parent.addCImportPaths(child.cImportPaths); parent.addStringImportPaths(child.stringImportPaths); parent.addInjectSourceFiles(child.injectSourceFiles); // linker stuff propagates up from static *and* dynamic library deps @@ -1047,6 +1048,7 @@ env["LIBS"] = join(build_settings.libs, " "); env["SOURCE_FILES"] = join(build_settings.sourceFiles, " "); env["IMPORT_PATHS"] = join(build_settings.importPaths, " "); + env["C_IMPORT_PATHS"] = join(build_settings.cImportPaths, " "); env["STRING_IMPORT_PATHS"] = join(build_settings.stringImportPaths, " "); env["DC"] = settings.platform.compilerBinary; diff --git a/source/dub/generators/visuald.d b/source/dub/generators/visuald.d index a5feb5f..1524a18 100644 --- a/source/dub/generators/visuald.d +++ b/source/dub/generators/visuald.d @@ -303,8 +303,10 @@ // include paths and string imports string imports = join(getPathSettings!"importPaths"(), " "); + string cimports = join(getPathSettings!"cImportPaths"(), " "); string stringImports = join(getPathSettings!"stringImportPaths"(), " "); - ret.formattedWrite(" %s\n", imports); + string combinedImports = join([imports, cimports], " "); + ret.formattedWrite(" %s\n", combinedImports); ret.formattedWrite(" %s\n", stringImports); ret.formattedWrite(" %s\n", "$(DMDInstallDir)windows\\bin\\dmd.exe"); // FIXME: use the actually selected compiler! diff --git a/source/dub/internal/utils.d b/source/dub/internal/utils.d index 28127ef..b9109cc 100644 --- a/source/dub/internal/utils.d +++ b/source/dub/internal/utils.d @@ -559,13 +559,13 @@ { import std.algorithm : map; import std.array : array; - import std.range : walkLength; + import std.range : walkLength, chain; assert(base_path.absolute); if (!file.absolute) file = base_path ~ file; size_t path_skip = 0; - foreach (ipath; settings.importPaths.map!(p => NativePath(p))) { + foreach (ipath; chain(settings.importPaths, settings.cImportPaths).map!(p => NativePath(p))) { if (!ipath.absolute) ipath = base_path ~ ipath; assert(!ipath.empty); if (file.startsWith(ipath) && ipath.bySegment.walkLength > path_skip) diff --git a/source/dub/package_.d b/source/dub/package_.d index 368f807..27f696d 100644 --- a/source/dub/package_.d +++ b/source/dub/package_.d @@ -623,6 +623,7 @@ ret.versions = bs.versions; ret.debugVersions = bs.debugVersions; ret.importPaths = bs.importPaths; + ret.cImportPaths = bs.cImportPaths; ret.stringImportPaths = bs.stringImportPaths; ret.preGenerateCommands = bs.preGenerateCommands; ret.postGenerateCommands = bs.postGenerateCommands; diff --git a/source/dub/packagemanager.d b/source/dub/packagemanager.d index 04c82e3..0300ba1 100644 --- a/source/dub/packagemanager.d +++ b/source/dub/packagemanager.d @@ -1298,29 +1298,8 @@ if (!path.existsDirectory()) return; - logDebug("iterating dir %s", path.toNativeString()); - try foreach (pdir; iterateDirectory(path)) { - logDebug("iterating dir %s entry %s", path.toNativeString(), pdir.name); - if (!pdir.isDirectory) continue; - - // Old / flat directory structure, used in non-standard path - // Packages are stored in $ROOT/$SOMETHING/` - auto pack_path = path ~ (pdir.name ~ "/"); - auto packageFile = Package.findPackageFile(pack_path); - - // New (since 2015) managed structure: - // $ROOT/$NAME-$VERSION/$NAME - // This is the most common code path - if (mgr.isManagedPath(path) && packageFile.empty) { - foreach (subdir; iterateDirectory(path ~ (pdir.name ~ "/"))) - if (subdir.isDirectory && pdir.name.startsWith(subdir.name)) { - pack_path ~= subdir.name ~ "/"; - packageFile = Package.findPackageFile(pack_path); - break; - } - } - - if (packageFile.empty) continue; + void loadInternal (NativePath pack_path, NativePath packageFile) + { Package p; try { foreach (pp; existing_packages) @@ -1338,6 +1317,38 @@ logDiagnostic("Full error: %s", e.toString().sanitize()); } } + + logDebug("iterating dir %s", path.toNativeString()); + try foreach (pdir; iterateDirectory(path)) { + logDebug("iterating dir %s entry %s", path.toNativeString(), pdir.name); + if (!pdir.isDirectory) continue; + + // Old / flat directory structure, used in non-standard path + // Packages are stored in $ROOT/$SOMETHING/` + const pack_path = path ~ (pdir.name ~ "/"); + auto packageFile = Package.findPackageFile(pack_path); + if (!packageFile.empty) { + // Deprecated unmanaged directory structure + logWarn("Package at path '%s' should be under '%s'", + pack_path.toNativeString().color(Mode.bold), + (pack_path ~ "$VERSION" ~ pdir.name).toNativeString().color(Mode.bold)); + logWarn("The package will no longer be detected starting from v1.42.0"); + loadInternal(pack_path, packageFile); + } + + // Managed structure: $ROOT/$NAME/$VERSION/$NAME + // This is the most common code path + else if (mgr.isManagedPath(path)) { + // Iterate over versions of a package + foreach (versdir; iterateDirectory(pack_path)) { + if (!versdir.isDirectory) continue; + auto vers_path = pack_path ~ versdir.name ~ (pdir.name ~ "/"); + if (!vers_path.existsDirectory()) continue; + packageFile = Package.findPackageFile(vers_path); + loadInternal(vers_path, packageFile); + } + } + } catch (Exception e) logDiagnostic("Failed to enumerate %s packages: %s", path.toNativeString(), e.toString()); } @@ -1417,9 +1428,7 @@ */ private NativePath getPackagePath (string name, string vers) { - // + has special meaning for Optlink - string clean_vers = vers.chompPrefix("~").replace("+", "_"); - NativePath result = this.packagePath ~ (name ~ "-" ~ clean_vers); + NativePath result = this.packagePath ~ name ~ vers; result.endsWithSlash = true; return result; } diff --git a/source/dub/project.d b/source/dub/project.d index b22f73d..f68155a 100644 --- a/source/dub/project.d +++ b/source/dub/project.d @@ -934,6 +934,7 @@ case "versions": case "debugVersions": case "importPaths": + case "cImportPaths": case "stringImportPaths": case "options": auto bs = buildSettings.dup; @@ -943,6 +944,8 @@ auto ensureTrailingSlash = (string path) => path.endsWith(dirSeparator) ? path : path ~ dirSeparator; static if (attributeName == "importPaths") bs.importPaths = bs.importPaths.map!(ensureTrailingSlash).array(); + else static if (attributeName == "cImportPaths") + bs.cImportPaths = bs.cImportPaths.map!(ensureTrailingSlash).array(); else static if (attributeName == "stringImportPaths") bs.stringImportPaths = bs.stringImportPaths.map!(ensureTrailingSlash).array(); @@ -984,6 +987,7 @@ case "stringImportFiles": case "sourceFiles": case "importPaths": + case "CImportPaths": case "stringImportPaths": return values.map!(escapeShellFileName).array(); @@ -1060,7 +1064,7 @@ auto getFixedBuildSetting(Package pack) { // Is relative path(s) to a directory? enum isRelativeDirectory = - attributeName == "importPaths" || attributeName == "stringImportPaths" || + attributeName == "importPaths" || attributeName == "cImportPaths" || attributeName == "stringImportPaths" || attributeName == "targetPath" || attributeName == "workingDirectory"; // Is relative path(s) to a file? @@ -1327,6 +1331,7 @@ dst.addVersionFilters(processVars(project, pack, gsettings, settings.versionFilters, false, buildEnvs)); dst.addDebugVersionFilters(processVars(project, pack, gsettings, settings.debugVersionFilters, false, buildEnvs)); dst.addImportPaths(processVars(project, pack, gsettings, settings.importPaths, true, buildEnvs)); + dst.addCImportPaths(processVars(project, pack, gsettings, settings.cImportPaths, true, buildEnvs)); dst.addStringImportPaths(processVars(project, pack, gsettings, settings.stringImportPaths, true, buildEnvs)); dst.addRequirements(settings.requirements); dst.addOptions(settings.options); diff --git a/source/dub/recipe/json.d b/source/dub/recipe/json.d index 7993fa2..2f1e3e6 100644 --- a/source/dub/recipe/json.d +++ b/source/dub/recipe/json.d @@ -209,6 +209,7 @@ case "files": case "sourceFiles": bs.sourceFiles[suffix] = deserializeJson!(string[])(value); break; case "sourcePaths": bs.sourcePaths[suffix] = deserializeJson!(string[])(value); break; + case "cSourcePaths": bs.cSourcePaths[suffix] = deserializeJson!(string[])(value); break; case "sourcePath": bs.sourcePaths[suffix] ~= [value.get!string]; break; // deprecated case "excludedSourceFiles": bs.excludedSourceFiles[suffix] = deserializeJson!(string[])(value); break; case "injectSourceFiles": bs.injectSourceFiles[suffix] = deserializeJson!(string[])(value); break; @@ -219,6 +220,7 @@ case "-versionFilters": bs.versionFilters[suffix] = deserializeJson!(string[])(value); break; case "-debugVersionFilters": bs.debugVersionFilters[suffix] = deserializeJson!(string[])(value); break; case "importPaths": bs.importPaths[suffix] = deserializeJson!(string[])(value); break; + case "cImportPaths": bs.cImportPaths[suffix] = deserializeJson!(string[])(value); break; case "stringImportPaths": bs.stringImportPaths[suffix] = deserializeJson!(string[])(value); break; case "preGenerateCommands": bs.preGenerateCommands[suffix] = deserializeJson!(string[])(value); break; case "postGenerateCommands": bs.postGenerateCommands[suffix] = deserializeJson!(string[])(value); break; @@ -279,6 +281,7 @@ foreach (suffix, arr; bs.libs) ret[withSuffix("libs", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.sourceFiles) ret[withSuffix("sourceFiles", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.sourcePaths) ret[withSuffix("sourcePaths", suffix)] = serializeToJson(arr); + foreach (suffix, arr; bs.cSourcePaths) ret[withSuffix("cSourcePaths", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.excludedSourceFiles) ret[withSuffix("excludedSourceFiles", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.injectSourceFiles) ret[withSuffix("injectSourceFiles", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.copyFiles) ret[withSuffix("copyFiles", suffix)] = serializeToJson(arr); @@ -288,6 +291,7 @@ foreach (suffix, arr; bs.versionFilters) ret[withSuffix("-versionFilters", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.debugVersionFilters) ret[withSuffix("-debugVersionFilters", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.importPaths) ret[withSuffix("importPaths", suffix)] = serializeToJson(arr); + foreach (suffix, arr; bs.cImportPaths) ret[withSuffix("cImportPaths", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.stringImportPaths) ret[withSuffix("stringImportPaths", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.preGenerateCommands) ret[withSuffix("preGenerateCommands", suffix)] = serializeToJson(arr); foreach (suffix, arr; bs.postGenerateCommands) ret[withSuffix("postGenerateCommands", suffix)] = serializeToJson(arr); diff --git a/source/dub/recipe/packagerecipe.d b/source/dub/recipe/packagerecipe.d index 909e653..c8bb5ec 100644 --- a/source/dub/recipe/packagerecipe.d +++ b/source/dub/recipe/packagerecipe.d @@ -426,6 +426,7 @@ @StartsWith("libs") string[][string] libs; @StartsWith("sourceFiles") string[][string] sourceFiles; @StartsWith("sourcePaths") string[][string] sourcePaths; + @StartsWith("cSourcePaths") string[][string] cSourcePaths; @StartsWith("excludedSourceFiles") string[][string] excludedSourceFiles; @StartsWith("injectSourceFiles") string[][string] injectSourceFiles; @StartsWith("copyFiles") string[][string] copyFiles; @@ -435,6 +436,7 @@ @StartsWith("versionFilters") string[][string] versionFilters; @StartsWith("debugVersionFilters") string[][string] debugVersionFilters; @StartsWith("importPaths") string[][string] importPaths; + @StartsWith("cImportPaths") string[][string] cImportPaths; @StartsWith("stringImportPaths") string[][string] stringImportPaths; @StartsWith("preGenerateCommands") string[][string] preGenerateCommands; @StartsWith("postGenerateCommands") string[][string] postGenerateCommands; @@ -524,14 +526,18 @@ return files.data; } - // collect source files + // collect source files. Note: D source from 'sourcePaths' and C sources from 'cSourcePaths' are joint into 'sourceFiles' dst.addSourceFiles(collectFiles(sourcePaths, "*.d")); + dst.addSourceFiles(collectFiles(cSourcePaths, "*.{c,i}")); auto sourceFiles = dst.sourceFiles.sort(); // collect import files and remove sources import std.algorithm : copy, setDifference; - auto importFiles = collectFiles(importPaths, "*.{d,di}").sort(); + auto importFiles = + chain(collectFiles(importPaths, "*.{d,di}"), collectFiles(cImportPaths, "*.h")) + .array() + .sort(); immutable nremoved = importFiles.setDifference(sourceFiles).copy(importFiles.release).length; importFiles = importFiles[0 .. $ - nremoved]; dst.addImportFiles(importFiles.release); @@ -551,6 +557,7 @@ getPlatformSetting!("versionFilters", "addVersionFilters")(dst, platform); getPlatformSetting!("debugVersionFilters", "addDebugVersionFilters")(dst, platform); getPlatformSetting!("importPaths", "addImportPaths")(dst, platform); + getPlatformSetting!("cImportPaths", "addCImportPaths")(dst, platform); getPlatformSetting!("stringImportPaths", "addStringImportPaths")(dst, platform); getPlatformSetting!("preGenerateCommands", "addPreGenerateCommands")(dst, platform); getPlatformSetting!("postGenerateCommands", "addPostGenerateCommands")(dst, platform); diff --git a/source/dub/recipe/sdl.d b/source/dub/recipe/sdl.d index 9e10e49..012268e 100644 --- a/source/dub/recipe/sdl.d +++ b/source/dub/recipe/sdl.d @@ -145,6 +145,7 @@ case "libs": setting.parsePlatformStringArray(bs.libs); break; case "sourceFiles": setting.parsePlatformStringArray(bs.sourceFiles); break; case "sourcePaths": setting.parsePlatformStringArray(bs.sourcePaths); break; + case "cSourcePaths": setting.parsePlatformStringArray(bs.cSourcePaths); break; case "excludedSourceFiles": setting.parsePlatformStringArray(bs.excludedSourceFiles); break; case "mainSourceFile": bs.mainSourceFile = setting.stringTagValue; break; case "injectSourceFiles": setting.parsePlatformStringArray(bs.injectSourceFiles); break; @@ -155,6 +156,7 @@ case "x:versionFilters": setting.parsePlatformStringArray(bs.versionFilters); break; case "x:debugVersionFilters": setting.parsePlatformStringArray(bs.debugVersionFilters); break; case "importPaths": setting.parsePlatformStringArray(bs.importPaths); break; + case "cImportPaths": setting.parsePlatformStringArray(bs.cImportPaths); break; case "stringImportPaths": setting.parsePlatformStringArray(bs.stringImportPaths); break; case "preGenerateCommands": setting.parsePlatformStringArray(bs.preGenerateCommands); break; case "postGenerateCommands": setting.parsePlatformStringArray(bs.postGenerateCommands); break; @@ -284,6 +286,7 @@ foreach (suffix, arr; bs.libs) adda("libs", suffix, arr); foreach (suffix, arr; bs.sourceFiles) adda("sourceFiles", suffix, arr); foreach (suffix, arr; bs.sourcePaths) adda("sourcePaths", suffix, arr); + foreach (suffix, arr; bs.cSourcePaths) adda("cSourcePaths", suffix, arr); foreach (suffix, arr; bs.excludedSourceFiles) adda("excludedSourceFiles", suffix, arr); foreach (suffix, arr; bs.injectSourceFiles) adda("injectSourceFiles", suffix, arr); foreach (suffix, arr; bs.copyFiles) adda("copyFiles", suffix, arr); @@ -293,6 +296,7 @@ foreach (suffix, arr; bs.versionFilters) adda("versionFilters", suffix, arr, "x"); foreach (suffix, arr; bs.debugVersionFilters) adda("debugVersionFilters", suffix, arr, "x"); foreach (suffix, arr; bs.importPaths) adda("importPaths", suffix, arr); + foreach (suffix, arr; bs.cImportPaths) adda("cImportPaths", suffix, arr); foreach (suffix, arr; bs.stringImportPaths) adda("stringImportPaths", suffix, arr); foreach (suffix, arr; bs.preGenerateCommands) adda("preGenerateCommands", suffix, arr); foreach (suffix, arr; bs.postGenerateCommands) adda("postGenerateCommands", suffix, arr); @@ -476,6 +480,8 @@ sourceFiles "source3" sourcePaths "sourcepath1" "sourcepath2" sourcePaths "sourcepath3" +cSourcePaths "csourcepath1" "csourcepath2" +cSourcePaths "csourcepath3" excludedSourceFiles "excluded1" "excluded2" excludedSourceFiles "excluded3" mainSourceFile "main source" @@ -496,6 +502,8 @@ x:debugVersionFilters importPaths "import1" "import2" importPaths "import3" +cImportPaths "cimport1" "cimport2" +cImportPaths "cimport3" stringImportPaths "string1" "string2" stringImportPaths "string3" preGenerateCommands "preg1" "preg2" @@ -579,6 +587,7 @@ assert(rec.buildSettings.libs == ["": ["lib1", "lib2", "lib3"]]); assert(rec.buildSettings.sourceFiles == ["": ["source1", "source2", "source3"]]); assert(rec.buildSettings.sourcePaths == ["": ["sourcepath1", "sourcepath2", "sourcepath3"]]); + assert(rec.buildSettings.cSourcePaths == ["": ["csourcepath1", "csourcepath2", "csourcepath3"]]); assert(rec.buildSettings.excludedSourceFiles == ["": ["excluded1", "excluded2", "excluded3"]]); assert(rec.buildSettings.mainSourceFile == "main source"); assert(rec.buildSettings.sourceFiles == ["": ["source1", "source2", "source3"]]); @@ -589,6 +598,7 @@ assert(rec.buildSettings.versionFilters == ["": ["version1", "version2", "version3"]]); assert(rec.buildSettings.debugVersionFilters == ["": ["debug1", "debug2", "debug3"]]); assert(rec.buildSettings.importPaths == ["": ["import1", "import2", "import3"]]); + assert(rec.buildSettings.cImportPaths == ["": ["cimport1", "cimport2", "cimport3"]]); assert(rec.buildSettings.stringImportPaths == ["": ["string1", "string2", "string3"]]); assert(rec.buildSettings.preGenerateCommands == ["": ["preg1", "preg2", "preg3"]]); assert(rec.buildSettings.postGenerateCommands == ["": ["postg1", "postg2", "postg3"]]); @@ -673,6 +683,13 @@ } unittest { + auto sdl = "name \"test\"\ncSourcePaths"; + PackageRecipe rec; + parseSDL(rec, sdl, null, "testfile"); + assert("" in rec.buildSettings.cSourcePaths); +} + +unittest { auto sdl = `name "test" dependency "package" repository="git+https://some.url" version="12345678" diff --git a/test/dpath-variable.sh b/test/dpath-variable.sh index 7e68020..db4ac1d 100755 --- a/test/dpath-variable.sh +++ b/test/dpath-variable.sh @@ -6,7 +6,7 @@ cd "${CURR_DIR}/dpath-variable" "${DUB}" upgrade -if [[ ! -f "$DPATH/dub/packages/gitcompatibledubpackage-1.0.1/gitcompatibledubpackage/dub.json" ]]; then +if [[ ! -f "$DPATH/dub/packages/gitcompatibledubpackage/1.0.1/gitcompatibledubpackage/dub.json" ]]; then die $LINENO 'Did not get dependencies installed into $DPATH.' fi @@ -24,6 +24,6 @@ "${DUB}" upgrade -if [[ ! -f "$DPATH_ALIAS/dub2/packages/gitcompatibledubpackage-1.0.1/gitcompatibledubpackage/dub.json" ]]; then +if [[ ! -f "$DPATH_ALIAS/dub2/packages/gitcompatibledubpackage/1.0.1/gitcompatibledubpackage/dub.json" ]]; then die $LINENO 'Did not get dependencies installed into dubHome (set from config).' fi diff --git a/test/interactive-remove.sh b/test/interactive-remove.sh index ee5f5a3..8919fef 100755 --- a/test/interactive-remove.sh +++ b/test/interactive-remove.sh @@ -9,32 +9,32 @@ # we need to nuke every `dub` version in the user cache... $DUB remove dub -n || true -$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub-1.9.0/dub ] -$DUB fetch dub@1.10.0 && [ -d $HOME/.dub/packages/dub-1.10.0/dub ] +$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub/1.9.0/dub ] +$DUB fetch dub@1.10.0 && [ -d $HOME/.dub/packages/dub/1.10.0/dub ] echo 1 | $DUB remove dub | tr -d '\n' | grep --ignore-case 'select.*1\.9\.0.*1\.10\.0.*' -if [ -d $HOME/.dub/packages/dub-1.9.0/dub ]; then +if [ -d $HOME/.dub/packages/dub/1.9.0/dub ]; then die $LINENO 'Failed to remove dub-1.9.0' fi -$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub-1.9.0/dub ] +$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub/1.9.0/dub ] # EOF aborts remove echo -xn '' | $DUB remove dub -if [ ! -d $HOME/.dub/packages/dub-1.9.0/dub ] || [ ! -d $HOME/.dub/packages/dub-1.10.0/dub ]; then +if [ ! -d $HOME/.dub/packages/dub/1.9.0/dub ] || [ ! -d $HOME/.dub/packages/dub/1.10.0/dub ]; then die $LINENO 'Aborted dub still removed a package' fi # validates input echo -e 'abc\n4\n-1\n3' | $DUB remove dub -if [ -d $HOME/.dub/packages/dub-1.9.0/dub ] || [ -d $HOME/.dub/packages/dub-1.10.0/dub ]; then +if [ -d $HOME/.dub/packages/dub/1.9.0/dub ] || [ -d $HOME/.dub/packages/dub/1.10.0/dub ]; then die $LINENO 'Failed to remove all version of dub' fi -$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub-1.9.0/dub ] -$DUB fetch dub@1.10.0 && [ -d $HOME/.dub/packages/dub-1.10.0/dub ] +$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub/1.9.0/dub ] +$DUB fetch dub@1.10.0 && [ -d $HOME/.dub/packages/dub/1.10.0/dub ] # is non-interactive with a $DUB remove dub@1.9.0 $DUB remove dub@1.10.0 -if [ -d $HOME/.dub/packages/dub-1.9.0/dub ] || [ -d $HOME/.dub/packages/dub-1.10.0/dub ]; then +if [ -d $HOME/.dub/packages/dub/1.9.0/dub ] || [ -d $HOME/.dub/packages/dub/1.10.0/dub ]; then die $LINENO 'Failed to non-interactively remove specified versions' fi diff --git a/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl b/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl deleted file mode 100644 index 650050d..0000000 --- a/test/issue838-custom-cache-paths/cache/foo-1.0.0/foo/dub.sdl +++ /dev/null @@ -1,3 +0,0 @@ -name "foo" -version "1.0.0" -targetType "sourceLibrary" diff --git a/test/issue838-custom-cache-paths/cache/foo/1.0.0/foo/dub.sdl b/test/issue838-custom-cache-paths/cache/foo/1.0.0/foo/dub.sdl new file mode 100644 index 0000000..650050d --- /dev/null +++ b/test/issue838-custom-cache-paths/cache/foo/1.0.0/foo/dub.sdl @@ -0,0 +1,3 @@ +name "foo" +version "1.0.0" +targetType "sourceLibrary" diff --git a/test/run-unittest.sh b/test/run-unittest.sh index a7c3427..00786e6 100755 --- a/test/run-unittest.sh +++ b/test/run-unittest.sh @@ -37,11 +37,22 @@ CURR_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd) FRONTEND="${FRONTEND:-}" +if [ -z ${FRONTEND:-} ]; then + if [ "$DC_BIN" == "ldc2" ]; then + FRONTEND=$(ldc2 --version | grep -Po "based on DMD v\K(2\.\d+\.\d)") + fi + if [ "$DC_BIN" == "dmd" ]; then + FRONTEND=$(dmd --version | grep -Po "D Compiler v\K(2\.\d+\.\d)") + fi +fi + +echo "Running unittests with $DC_BIN (frontend=$FRONTEND)" + if [ "$#" -gt 0 ]; then FILTER=$1; else FILTER=".*"; fi for pack in $(ls -d $CURR_DIR/*/); do if [[ ! "$pack" =~ $FILTER ]]; then continue; fi - if [ -e $pack/.min_frontend ] && [ ! -z "$FRONTEND" -a "$FRONTEND" \< $(cat $pack/.min_frontend) ]; then continue; fi + if [ -f $pack/.min_frontend ] && [ ! -z "$FRONTEND" -a "$FRONTEND" \< $(cat $pack/.min_frontend) ]; then continue; fi # First we build the packages if [ ! -e $pack/.no_build ] && [ ! -e $pack/.no_build_$DC_BIN ]; then # For sourceLibrary diff --git a/test/test_registry.d b/test/test_registry.d index f50f38b..cb9790f 100755 --- a/test/test_registry.d +++ b/test/test_registry.d @@ -1,10 +1,16 @@ #!/usr/bin/env dub /+dub.sdl: -dependency "vibe-d" version="~>0.9" +dependency "vibe-d:http" version="~>0.9" versions "VibeNoSSL" +/ -import vibe.d; +import std.array; +import vibe.core.args; +import vibe.core.core; +import vibe.core.path; +import vibe.http.fileserver; +import vibe.http.router; +import vibe.http.server; /* Provide a special API File Handler as Vibe.d's builtin serveStaticFiles diff --git a/test/use-c-sources/.min_frontend b/test/use-c-sources/.min_frontend new file mode 100644 index 0000000..1dbb4ff --- /dev/null +++ b/test/use-c-sources/.min_frontend @@ -0,0 +1 @@ +2.101 diff --git a/test/use-c-sources/dub.json b/test/use-c-sources/dub.json new file mode 100644 index 0000000..c1d1c45 --- /dev/null +++ b/test/use-c-sources/dub.json @@ -0,0 +1,11 @@ +{ + "toolchainRequirements": { + "dub": ">=1.29.0", + "frontend": ">=2.101.0" + }, + "cSourcePaths": [ + "source" + ], + "description": "A minimal D application using ImportC and C sources in a dub project.", + "name": "use-c-sources" +} \ No newline at end of file diff --git a/test/use-c-sources/source/app.d b/test/use-c-sources/source/app.d new file mode 100644 index 0000000..e00eaca --- /dev/null +++ b/test/use-c-sources/source/app.d @@ -0,0 +1,37 @@ +/** Some test code for ImportC */ +module app.d; + +import std.algorithm.iteration; +import std.array; +import std.conv; +import std.exception; +import std.range; +import std.stdio; +import std.string; + +import some_c_code; + +void main() +{ + doCCalls(); +} + +/// Call C functions in zstd_binding module +void doCCalls() +{ + relatedCode(42); + + ulong a = 3; + uint b = 4; + auto rs0 = multiplyU64byU32(&a, &b); + writeln("Result of multiplyU64byU32(3,4) = ", rs0); + + uint[8] arr = [1, 2, 3, 4, 5, 6, 7, 8]; + auto rs1 = multiplyAndAdd(arr.ptr, arr.length, 3); + writeln("Result of sum(%s*3) = ".format(arr), rs1); + + foreach (n; 1 .. 20) + { + writeln("fac(", n, ") = ", fac(n)); + } +} diff --git a/test/use-c-sources/source/some_c_code.c b/test/use-c-sources/source/some_c_code.c new file mode 100644 index 0000000..487e52d --- /dev/null +++ b/test/use-c-sources/source/some_c_code.c @@ -0,0 +1,34 @@ + +#include + +#include "some_c_code.h" + +// Some test functions follow to proof that C code can be called from D main() + +void relatedCode(size_t aNumber) +{ + printf("Hallo! This is some output from C code! (%d)\n", aNumber); +} + +uint64_t multiplyU64byU32(uint64_t*a, uint32_t*b) +{ + return *a * *b; +} + +uint64_t multiplyAndAdd(uint32_t*arr, size_t arrlen, uint32_t mult) +{ + uint64_t acc = 0; + for (int i = 0; i < arrlen; i++) + { + acc += arr[i]*mult; + } + return acc; +} + +uint64_t fac(uint64_t n) +{ + if (n > 1) + return n * fac(n-1); + else + return 1; +} diff --git a/test/use-c-sources/source/some_c_code.h b/test/use-c-sources/source/some_c_code.h new file mode 100644 index 0000000..9643eb2 --- /dev/null +++ b/test/use-c-sources/source/some_c_code.h @@ -0,0 +1,12 @@ +#ifndef SOME_C_CODE_H +#define SOME_C_CODE_H + +#include +#include + +extern void relatedCode(size_t aNumber); +extern uint64_t multiplyU64byU32(uint64_t*a, uint32_t*b); +extern uint64_t multiplyAndAdd(uint32_t*arr, size_t arrlen, uint32_t mult); +extern uint64_t fac(uint64_t n); + +#endif \ No newline at end of file diff --git a/test/version-spec.sh b/test/version-spec.sh index 498d59f..053d177 100755 --- a/test/version-spec.sh +++ b/test/version-spec.sh @@ -43,10 +43,10 @@ $DUB remove-local "$CURR_DIR/version-spec/newfoo" $DUB remove-local "$CURR_DIR/version-spec/oldfoo" -$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub-1.9.0/dub ] -$DUB fetch dub=1.10.0 && [ -d $HOME/.dub/packages/dub-1.10.0/dub ] +$DUB fetch dub@1.9.0 && [ -d $HOME/.dub/packages/dub/1.9.0/dub ] +$DUB fetch dub=1.10.0 && [ -d $HOME/.dub/packages/dub/1.10.0/dub ] $DUB remove dub@1.9.0 $DUB remove dub=1.10.0 -if [ -d $HOME/.dub/packages/dub-1.9.0/dub ] || [ -d $HOME/.dub/packages/dub-1.10.0/dub ]; then +if [ -d $HOME/.dub/packages/dub/1.9.0/dub ] || [ -d $HOME/.dub/packages/dub/1.10.0/dub ]; then die $LINENO 'Failed to remove specified versions' fi