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