dub
dub copied to clipboard
Configuration "unittest" leads to error "only one main... allowed"
I use configuration "unittest" to add a dependency to a unittest framework. But there is some strange behavior which an unexperienced developer cannot understand.
Execute command: dub init bug1
Add configurations to dub.json
"configurations": [
{
"name": "debug"
},
{
"name": "unittest"
}
]
Issue 1: Although the package contains an app.d file, running command "dub test" will detect the targetType "library". Target type library will add itself a void main method which will now lead to error:
Generating test runner configuration 'bug1-test-unittest' for 'unittest' (library).
...
source\app.d(3,6): Error: only one main/WinMain/DllMain allowed. Previously found main at ..\..\AppData\Local\Temp\dub_test_root-4ddc4093-e161-491c-b61b-b8f1c8b719fd.d(9,12)
There is no information, that the second main method was generated by dub. Although why is target type "library" detected?
Issue 2:: Attribute mainSourceFile is quite hard to understand. By adding this attribute, app.d is excluded from the compilation (...Excluding main source file source/app.d from test...)
{
"name": "unittest",
"mainSourceFile": "source/app.d"
}
What is hard to understand is following: If I now also add attribute "targetType = executable" then mainSourceFile attribute is ignored and app.d isn't excluded anymore.
If this behavior is the expected / designed behavior, could you please add some sentences on the documentation (https://code.dlang.org/package-format?lang=json) explaining the mechanics: unittest > library -> auto generated main -> mainSourceFile -> targetType Executable
This is quite annoying if all one wants to do is to e.g. simply start a script before/after building a unittest. Adding the "unittest" configuration somehow breaks the "normal" unittest behaviour. See below example.
$ dub --version
DUB version 1.9.0, built on Jun 7 2018
Minimal example
source/app.d
:
void main(){}
dub.sdl
:
name "test"
Output of dub test --verbose
(succeeds):
Using dub registry url 'https://code.dlang.org/'
Refreshing local packages (refresh existing: true)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Note: Failed to determine version of package mytest at .. Assuming ~master.
Refreshing local packages (refresh existing: false)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Refreshing local packages (refresh existing: false)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Checking for upgrades.
Using cached upgrade results...
No source files found in configuration 'library'. Falling back to "dub -b unittest".
Configuring dependent mytest, deps:
Performing "unittest" build using /Library/D/dmd/bin/dmd for x86_64.
mytest ~master: building configuration "application"...
/Library/D/dmd/bin/dmd -c -of.dub/build/application-unittest-posix.osx-x86_64-dmd_2080-6878B1D82B97B3507BAD24C0266CCBB5/mytest.o -debug -g -unittest -w -version=Have_mytest -Isource/ source/app.d -vcolumns
Linking...
/Library/D/dmd/bin/dmd -of.dub/build/application-unittest-posix.osx-x86_64-dmd_2080-6878B1D82B97B3507BAD24C0266CCBB5/mytest .dub/build/application-unittest-posix.osx-x86_64-dmd_2080-6878B1D82B97B3507BAD24C0266CCBB5/mytest.o -g
Copying target from /Users/Timoses/programs/dotfim/mytest/.dub/build/application-unittest-posix.osx-x86_64-dmd_2080-6878B1D82B97B3507BAD24C0266CCBB5/mytest to /Users/Timoses/programs/dotfim/mytest
Running ./mytest
Now let's break it
Change dub.sdl
to:
name "test"
configuration "unittest" {
preBuildCommands "echo \"HELLO\""
}
Output of dub test --verbose
(fails):
Using dub registry url 'https://code.dlang.org/'
Refreshing local packages (refresh existing: true)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Ignoring version specification (>=0.0.0) for path based dependency .
Note: Failed to determine version of package mytest at .. Assuming ~master.
Refreshing local packages (refresh existing: false)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Refreshing local packages (refresh existing: false)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Checking for upgrades.
Using cached upgrade results...
Generating test runner configuration 'mytest-test-unittest' for 'unittest' (library).
Get module name from path: /Users/Timoses/programs/dotfim/mytest/source/app.d
Refreshing local packages (refresh existing: false)...
Looking for local package map at /var/lib/dub/packages/local-packages.json
Looking for local package map at /Users/Timoses/.dub/packages/local-packages.json
Try to load local package map at /Users/Timoses/.dub/packages/local-packages.json
Configuring dependent mytest, deps:
Performing "unittest" build using /Library/D/dmd/bin/dmd for x86_64.
mytest ~master: building configuration "mytest-test-unittest"...
Running pre-build commands...
Running echo "HELLO"
HELLO
/Library/D/dmd/bin/dmd -c -of.dub/build/mytest-test-unittest-unittest-posix.osx-x86_64-dmd_2080-EBCD2572FBC9DD092DC8E29B010CF88C/mytest-test-unittest.o -debug -g -unittest -w -version=VibeCustomMain -version=Have_mytest -Isource/ /var/folders/xf/n9z8fjbd0tx4l6t3h1l1n4_00000gn/T/dub_test_root-286ff5ba-2ea5-4569-8532-bb47822835eb.d source/app.d -vcolumns
source/app.d(1,6): Error: only one `main` allowed. Previously found `main` at /var/folders/xf/n9z8fjbd0tx4l6t3h1l1n4_00000gn/T/dub_test_root-286ff5ba-2ea5-4569-8532-bb47822835eb.d(9,12)
FAIL .dub/build/mytest-test-unittest-unittest-posix.osx-x86_64-dmd_2080-EBCD2572FBC9DD092DC8E29B010CF88C/ mytest-test-unittest executable
/Library/D/dmd/bin/dmd failed with exit code 1.
In the working case the output shows
No source files found in configuration 'library'. Falling back to "dub -b unittest".
whereas that is not shown in the non-working output.
The behaviour feels very opaque. Apparently, specifying the unittest configuration overwrites the behaviour.
One could specify in dub.sdl
:
configuration "unittest" {
buildOptions "unittests"
}
However, that still fails with "only one main allowed. ...". Additionally it tells that user:
## Warning for package mytest, configuration unittest ##
The following compiler flags have been specified in the package description
file. They are handled by DUB and direct use in packages is discouraged.
Alternatively, you can set the DFLAGS environment variable to pass custom flags
to the compiler, or use one of the suggestions below:
unittests: Call DUB with --build=unittest
Well.. How then should a custom "unittest" configuration be set up? And what are the quirks behind the scene that make dub test
work in one case but not in the other?
Bump! Same issue. Is this going to be fixed? How should one trigger unittests in dub?
Use mainSourceFile
in your configuration. It will be automatically excluded from other configurations.
Use
mainSourceFile
in your configuration. It will be automatically excluded from other configurations.
Unfortunately, it doesn't work with dub test
:
"targetPath": "build",
"mainSourceFile": "alerter.d",
"sourcePaths": ["source"],
"copyFiles": ["./resources"],
"name": "alerter",
"buildTypes": {
"release": {
"buildOptions": [
"releaseMode",
"inline",
"optimize"
]
},
"tests": {
"buildOptions": [
"unittests"
]
}
}
}
Where is the configurations
array ?
What I meant was:
"configurations": [
{
"name": "debug",
"mainSourceFile": "source/alerter.d"
},
{
"name": "unittest"
}
]
Here is the current dub.json
{
"name": "alerter",
"sourcePaths": ["source"],
"copyFiles": ["./resources"],
"targetPath": "build",
"configurations": [
{
"name": "debug",
"mainSourceFile": "source/alerter.d"
},
{
"name": "unittest"
}
],
"buildTypes": {
"release": {
"buildOptions": [
"releaseMode",
"inline",
"optimize"
]
},
"tests": {
"buildOptions": [
"unittests"
]
}
}
}
And here is what I get, when I try to run dub build
in the project dir.
Performing "debug" build using /usr/local/bin/ldc for aarch64, arm_hardfloat.
alerter ~master: building configuration "alerter"...
Error: No source files
/usr/local/bin/ldc failed with exit code 1.
I tried dub -b
options and they also don't work.
alerter ~master: building configuration "alerter"...
So you aren't building the debug
configuration, and source/alerter.d
is excluded from the alerter
configuration.
alerter ~master: building configuration "alerter"...
So you aren't building the
debug
configuration, andsource/alerter.d
is excluded from thealerter
configuration.
Ok, dub -b debug
successfully builds the project. However, it uses the "library" target type by default and if I specify the "targetType" : "executable"
{
"name": "debug",
"mainSourceFile": "alerter.d",
"targetType": "executable"
}
I get :(
Performing "debug" build using /usr/local/bin/ldc for aarch64, arm_hardfloat.
alerter ~master: building configuration "debug"...
Error: module `alerter` is in file 'alerter.d' which cannot be read
import path[0] = source/
import path[1] = /Users/pavels/.local/share/ldc2/bin/../import
/usr/local/bin/ldc failed with exit code 1.
Do you have a working dub.json
by chance for a single executable script with a custom name?
I have run into this problem as well and while searching for answers, I ran into this GitHub issue. In the current dub version, the system does work, but it's quite confusing for newer engineers due to the following reasons:
- The implicitly generated
application
orlibrary
configurations are not visible, so there is no easy way to know that special logic was being done by default, and the user just assumes this is normal behavior. - The definition of any
configuration
causes the defaults to be lost, e.g. someone adding a special test configuration suddenly finds errors like this while simply trying to build the app or run unittests. - Even after the user discovers they must now re-write multiple configurations, the default behavior of the generated 'application' or 'library' configs is not documented, thus the engineer has to figure it out someone through trial and error.
With that being said, I find the following dub.sdl
does most of what is needed for my use case (having a separate integration test configuration that tests the fully built program from the outside):
authors "Vijay Nayar"
copyright "Copyright © 2019, Vijay Nayar"
description "Receives data from sources, converts it to protobufs, and delivers it in batches to stem."
license "proprietary"
name "mouth"
targetPath "target"
# By default, 'dub' creates either an 'application' or 'library' config if no configuration exists.
# Because we need a configuration for integration tests, this forces us to create the
# 'application' config as well.
# Used by 'dub build' and 'dub test', because it is the first 'executable' config present.
configuration "application" {
targetName "mouth"
targetType "executable"
# Your dependencies may vary.
dependency "funnel:common" path="../"
dependency "funnel:proto" path="../"
dependency "nanomsg-wrapper" version="~>0.5.3"
dependency "poodinis" version="~>8.0.3"
dependency "vibe-d" version="~>0.9.4"
# This must be listed so that 'dub test' knows to ignore it.
mainSourceFile "source/app.d"
}
# Used by 'dub test --config=integration'
configuration "integration" {
targetName "mouth_integration"
# This must not be 'library', or it will be used by 'dub test', which first looks for 'library' then 'executable' types.
targetType "executable"
# The "source/" directory is automatically included, it must be explicitly excluded instead.
excludedSourceFiles "source/*"
# The integration tests' source is in './integration'.
sourcePaths "integration"
importPaths "integration"
# Make sure the executable we are testing exists.
preBuildCommands "echo IMPORT_PATHS=$$IMPORT_PATHS"
preRunCommands "cd $PACKAGE_DIR ; dub build"
}