DQ Project Files (.dqproj)
Some projects may require a large amount of compiler options to compile. In order to make the complex project compilation easier the DQ compiler supports project files.
The DQ project files are basically a set of compiler options in a more manageable way.
The project files use the .dqproj extension:
Example usage:
dq-comp application.dqproj
dq-comp -O0 -g -o build/application application.dqproj
(the dq-comp options provided in the command line override the options in the .dqproj file)
Project File Example
// application.dqproj
packagepath = 'packages'
var BOARD_SUPPORT = PackagePath('board_support')
include '${BOARD_SUPPORT}/project/stm32f746.dqproj'
main = 'src/application.dq'
output = 'build/${PROJNAME}.elf'
target = 'arm_m7f-bare'
link = true
optlevel = 2
debuginfo = true
lto = false
define BOARD_NUCLEO_F746
define CPU_CLOCK_HZ = 216000000
linkobject = '${BOARD_SUPPORT}/lib/startup.o'
linkoption = '--gc-sections'
An included fragment might contain the shared target and linker configuration:
// board_support/project/stm32f746.dqproj
linkerpath = '${THIS_DIR}/../lib'
linkscript = '${THIS_DIR}/../ld/stm32f746.ld'
Lexical Rules
The format uses DQ-like identifiers, strings, comments, and statement terminators. Property and keyword names are case-sensitive.
An identifier starts with an ASCII letter or _ and may continue with ASCII
letters, decimal digits, or _:
FEATURE
CPU_CLOCK_HZ
board2
Strings may use single or double quotes. They must end on the same physical line on which they begin.
'src/main.dq'
"arm_m7f-bare"
The recognized string escapes are:
| Escape | Result |
|---|---|
\n |
newline character |
\r |
carriage return |
\t |
tab |
\\ |
backslash |
\" |
double quote |
\' |
single quote |
An unrecognized escape is preserved as a backslash followed by the escaped character.
Both DQ comment forms are supported:
// line comment
/* block
comment */
An unterminated string or block comment is an error.
Statements normally end at a newline. A semicolon is optional at the end of a statement and is required between multiple statements on the same line:
main = 'main.dq'
output = 'app'
main = 'main.dq'; output = 'app'
The parts of one statement, including =, its value, and the arguments of
PackagePath(), may not continue onto another line.
Statements
A project consists of property assignments and three special statements:
define, var, and include.
property = value
define NAME
define NAME = value
var NAME = value
include 'file.dqproj'
Unknown properties, invalid value types, trailing tokens, and duplicate single-value properties are errors.
Properties
| Property | Value | Repetition | Meaning |
|---|---|---|---|
main |
path string | once, required | DQ source file compiled as the project entry module. |
output |
path string | once, optional | Final executable or object filename. Normal compiler output defaults apply when omitted. |
target |
string | once, optional | Compiler target name, using the same names accepted by --target. |
packagepath |
path string | repeatable | Add a DQ package search root. |
link |
boolean | once, optional | Force linking when true; compile only when false. |
linkobject |
path string | repeatable | Add an existing object or other positional linker input. |
linkerpath |
path string | repeatable | Pass --library-path=<path> to the linker. |
linkoption |
string | repeatable | Pass one argument directly to the linker. |
linkscript |
path string | once, optional | Pass --script=<path> to the linker. |
debuginfo |
boolean | once, optional | Enable or disable debug information. |
optlevel |
integer 0 through 3 |
once, optional | Set the optimization level. |
lto |
boolean | once, optional | Enable full LTO when true; disable LTO when false. |
main is required only after the top-level file and all its includes have been
assembled. An included fragment therefore does not need its own main.
output is always optional.
The cpu, abi, and floatabi property names are reserved for future target
tuning. They are currently rejected as unsupported. They are not silently
ignored.
Link Mode
Without a link property, the compiler retains its automatic link mode:
- A hosted target links a module that contains
*Main. - A bare target produces an object by default.
link = true is equivalent to explicitly selecting --link. It can force a
bare target to link an ELF image. link = false is equivalent to -c and
always requests compile-only output.
Defines
define creates a symbol in the compiler's @def scope:
define FEATURE
define LOGGING = true
define TRACE = false
define BUFFER_SIZE = 4096
define OFFSET = -16
A define without a value has boolean value true. Explicit values are limited
to true, false, or a signed 64-bit decimal integer. Strings, hexadecimal
integers, expressions, and variables are not accepted as define values.
Define names are identifiers and must be unique throughout the assembled
project, including all included files. A command-line -DNAME or
-DNAME=value replaces the project define with the same name.
Project defines are inherited by imported child modules.
Paths
The following properties contain paths:
mainoutputpackagepathlinkobjectlinkerpathlinkscriptinclude
After variable expansion, a relative path is resolved against the directory of the file containing that statement. The result is converted to an absolute, lexically normalized path. This rule applies independently to every included file.
For example, in project/boards/board.dqproj:
linkscript = '../ld/board.ld'
the path is relative to project/boards, not to the process working directory
or the top-level project directory.
The project parser requires included files and PackagePath() results to
exist. It does not check the existence of main, output, packagepath,
linkobject, linkerpath, or linkscript; the compiler, filesystem, or linker
reports problems with those paths when they are used.
Variables
A variable stores a path for later substitution. Its value must be either a
quoted path string or the result of PackagePath():
var SOURCE_DIR = 'src'
var SDK = PackagePath('sdk')
main = '${SOURCE_DIR}/main.dq'
include '${SDK}/project/common.dqproj'
A relative quoted value is resolved against the directory of the file that declares the variable. Consequently, it keeps the same meaning when it is used later from a different included file.
Variable references use only the explicit ${NAME} form. Expansion is
performed inside all quoted project values, including path properties,
target, linkoption, include paths, and PackagePath() arguments.
Variable names are case-sensitive, must be declared before use, and are shared through includes. A variable cannot be declared more than once. User variables also cannot redefine either built-in variable:
| Variable | Meaning |
|---|---|
${PROJECT_NAME} |
Name of the top level .dqproj file, without extension |
${PROJECT_DIR} |
Directory containing the top-level .dqproj file. |
${THIS_DIR} |
Directory containing the file with the current statement. |
The project language does not expand environment variables, ~, $NAME, or
%NAME%. A dollar sign has no special meaning unless it starts ${NAME}.
Package Lookup
PackagePath() locates a package using the same package-root resolver as a DQ
use statement:
var SDK = PackagePath('sdk')
The argument must expand to one identifier. If /opt/dq/packages/sdk is the
selected package, the function returns the absolute normalized path
/opt/dq/packages/sdk, not /opt/dq/packages.
Package roots are searched from highest to lowest precedence:
- Command-line
--pkg-pathroots, with the last command-line root winning. - Project
packagepathroots already encountered, with the last project root winning. - Compiler default package roots, with the later default root winning.
Command-line package roots are collected before the project is evaluated, so
they are available to every PackagePath() call regardless of command-line
position. A project packagepath becomes available only after its statement is
evaluated. Includes follow the same textual ordering rule.
A missing package is a project-evaluation error.
Includes
An include inserts another .dqproj file at the point of the statement:
include 'common.dqproj'
include '${SDK}/project/board.dqproj'
The path is expanded and resolved relative to the including file. Included
files must also use the .dqproj extension.
Includes behave like textual insertion with file-local path anchoring:
- Variables declared before an include are visible inside it.
- Variables declared by an included file remain visible after it returns.
packagepathstatements affect laterPackagePath()calls.- Single-property, variable, and define duplicate checks span all files.
- Repeatable property ordering follows statement order across includes.
The same file may be included again after its earlier inclusion has completed. Normal duplicate rules still apply to the repeated statements. Including a file that is already active is a cycle and is rejected with the canonical include chain.
Linker Argument Ordering
linkerpath, linkscript, and linkoption produce linker arguments in their
assembled project statement order. Included statements retain their position in
that order. Command-line --linker-arg=<arg> entries follow all project linker
arguments.
The compiler constructs linker inputs in this order:
- The object generated for
main. - Objects generated for imported DQ modules.
- Project
linkobjectinputs, in statement order. -oand the final output filename.- Libraries requested by DQ modules.
Each project or command-line linker argument is passed through the compiler driver as one linker argument before those positional inputs.
Project parsing does not verify that linker objects, library paths, or linker scripts exist. Such errors are reported by the linker.
Command-Line Precedence
The project is parsed before normal command-line option evaluation and before target-dependent compiler initialization. Project values act as defaults; explicit command-line selections are then applied on top.
| Setting | Precedence |
|---|---|
| Target | --target overrides target; otherwise the project target overrides the host default. |
| Output | -o overrides output; otherwise normal output defaults apply when the property is absent. |
| Optimization | -O0 through -O3 override optlevel. |
| Debug information | -g enables debug information even when debuginfo = false. There is currently no command-line option to force it off. |
| LTO | --lto or --lto=full|off overrides lto. |
| Link mode | The first explicit -c or --link replaces the project mode. Conflicting subsequent command-line link modes are errors. |
| Defines | The first command-line definition of a name removes the project definition of that name. |
| Package roots | Command-line roots have higher lookup precedence than project and default roots. |
| Linker arguments | Project arguments precede command-line --linker-arg entries. |
The project target is selected early enough to initialize target-dependent
built-in types correctly. Imported child modules inherit the effective target,
optimization level, debug and LTO settings, defines, build settings, and package
roots through compiler arguments. Child compilations receive the resolved .dq
source file and do not parse the project again.
Errors and Diagnostics
Project evaluation stops at the first error. Diagnostics identify the file, line, column, diagnostic identifier, and message:
/work/app/application.dqproj(12,8) ERROR(ProjectValue): optlevel must be between 0 and 3
Project errors include, among others:
- unreadable project or include files;
- wrong project extensions;
- malformed strings, comments, or statements;
- unknown, duplicate, or unsupported properties;
- invalid property types or values;
- duplicate or unknown variables;
- duplicate project defines;
- missing packages;
- include cycles;
- an assembled project without
main.
Compact Grammar
The following grammar is descriptive. newline or ; terminates a statement,
and the final statement may end at end-of-file.
project := { terminator | statement terminator } [ statement ] EOF
statement := property '=' property-value
| 'define' identifier [ '=' define-value ]
| 'var' identifier '=' variable-value
| 'include' string
property := 'main' | 'output' | 'target' | 'packagepath'
| 'link' | 'linkobject' | 'linkerpath' | 'linkoption'
| 'linkscript' | 'debuginfo' | 'optlevel' | 'lto'
property-value := string | boolean | signed-decimal-integer
variable-value := string | 'PackagePath' '(' string ')'
define-value := boolean | signed-decimal-integer
boolean := 'true' | 'false'
terminator := newline | ';'
Whitespace and comments may occur between tokens as long as they do not move the remainder of the current statement onto another line.