How can I force the SConscript builder to change directory? - delphi

currently I'm trying to port a million-sloc legacy project from dull .cmd scripts to SCons. Parts of it are VC++, others are Delphi. Creating SConscripts for the C++ pieces was a breeze.
To build the delphi part I've written a very simple builder which detects whether it is a program or library project. Calling the builder after chaining via SConscript makes scons to call dcc32 $subdir/project.dpr what misleads dcc32 to look for units in the current directory instead of the $subdir.
Is there a way to tell scons to enter the $subdir before executing commands residing in the sconscript or should I fix it within the builder?
Thank you in advance

SCons already changes to the directory of sub-directory SConscripts when reading them, so it looks like the problem is going to have to be fixed in the actual builder.
Once the scripts are parsed, and SCons is running the build commands, it stays in the top-level directory. Commands are then issued using path names relative to that top-level directory. The way to change this behavior is to use the chdir keyword in your Builder.
The example from the scons man page is as follows:
b = Builder(action='build < ${SOURCE.file} > ${TARGET.file}',
chdir=1)
env = Environment(BUILDERS = {'MyBuild' : b})
env.MyBuild('sub/dir/foo.out', 'sub/dir/foo.in')
You need to specify the .file component as the use of chdir does not change the names passed to the builder, i.e. they are still relative to the top-level directory.

Related

What is the difference between the -i and -u parameters to the dcc command-line compilers?

What exactly is the -i option of the Delphi dcc command-line compilers (dcc32.exe, dcc64.exe, dcclinux64.exe and others)? As opposed to -u? Help just states this briefly (and Embarcadero documentation does not seem to expand upon the subject):
-I<paths> = Include directories
-U<paths> = Unit directories
For a while, I thought that -u is for including source code and -i for including precompiled .dcu files, but that does not seem to be the case. I also see cases where -i imports source code and -u imports .dcu files, and also that seems to work just fine. Another thought is that -u is meant to be the counterpart of the project's Search path in the Delphi IDE, and -i the counterpart of the Delphi IDE's global Library path, but that does not seem conclusive, either.
When should I use one or the other, -i or -u?
The Remarks section of this page http://docwiki.embarcadero.com/RADStudio/Sydney/en/Include_file_(Delphi) begins
The $I parameter directive instructs the compiler to include the named file in the compilation. In effect, the file is inserted in the compiled text right after the {$I filename} directive.
The default extension for filename is .pas. A filename specified with no file extension always gets the .pas extension. If the filename does not specify a directory path, then, in addition to searching for the file in the same directory as the current module, Delphi searches in the directories specified in the Search path input box on the Delphi Compiler page of the Project > Options dialog box (or in the directories specified in a -I option on the command line compiler). ..."
The important thing to understand is that this is not talking about searching for source files in general, but rather for single files named in a source file by an
{$inc }
or
{$include }
directive in a source file. For example
unit SomeUnit;
{$inc SomeIncludeFile}
interface
[...]
Files named inside an {$inc} or {$include} directive are known as "include files" - hence the title topic of the quoted page. Subject to the restriction noted in the final paragraph of the Remarks, the directive can appear pretty much anywhere in a source file and, during compilation, the compiler substitutes the contents of the named file for the directive (including the filename). The support for include files in Turbo Pascal pre-dates its support for units and was primarily to ensure that two or more source files could behave as if they contained identical text, for example shared code or definitions.
The -i setting tells the compiler one or more folders in which to look for files such as SomeIncludeFile which are named by include directives the compiler encounters while compiling the source files in a project.
The -u setting tells the compiler where to look for unit files (e.g. .Pas and .Dcu ones) during a compilation.

Project level environment variable in source path

I'd like to specify an environment variable for use in the source path (library path) at a project level.
We often have a couple of versions checked out of our SVN repository at the same time in different directories, and I'd like to specify the repository root for a project in relative terms at a project level. I could then use that path in a project's source path and I wouldn't have to include indecipherable dot dot slashes (..\) in paths.
For example, say I have checked out trunk to c:\projects\trunk. Then underneath there I have a project in <repositoryroot>\Foo\Bar\ under trunk which uses the Delphi Spring framework under <repositoryroot>\components\external\Spring4d. I end up with a whole bunch of directories in the search path with ..\..\External\Spring4D\Source at the beginning. For example ..\..\External\Spring4D\Source\Base\Collections. I would like to be able to be able to use ${Spring4D} instead, producing ${Spring4D}\Base\Collections\, which is much less wordy and it means that if you move a project or component you can change one value and it updates all paths.
I know that you can do this on a Delphi level by specifying paths in Delphi's environment variables, but I would like to achieve the same thing on a project level or repository level.
Does anyone have any ideas on how to achieve this? Are there any settings or even add-ins that would allow this sort of functionality?
You can manually edit your project file (.dproj) and add a variable there:
<PropertyGroup>
<MyVariableName>MyVariableContent</MyVariableName>
</PropertyGroup>
Later on, you can refer to the content of that variable:
<DCC_UnitSearchPath>C:\Components;$(MyVariableName)</DCC_UnitSearchPath>
You can also define a new environment variable (SystemPropertiesAdvanced.exe -> Environment variables -> Add) and then refer to that variable using the same syntax, e.g.:
<DCC_UnitSearchPath>C:\Components;$(PATH)</DCC_UnitSearchPath>
(Note that it is a very bad idea to use PATH here, it's only an example of a variable which will exist in your environment.)
You could also employ some cmd script magic to to create environment variables that point to those subdirectories and at the end call the IDE, so these environment variables are available in the IDE in the same way as global environment variables would be (see pepak's answer for that).
Pointers:
%0 is the name of the current cmd file
use tilde for file name parts

how to find and deploy the correct files with Bazel's pkg_tar() in Windows?

please take a look at the bin-win target in my repository here:
https://github.com/thinlizzy/bazelexample/blob/master/demo/BUILD#L28
it seems to be properly packing the executable inside a file named bin-win.tar.gz, but I still have some questions:
1- in my machine, the file is being generated at this directory:
C:\Users\John\AppData\Local\Temp_bazel_John\aS4O8v3V\execroot__main__\bazel-out\x64_windows-fastbuild\bin\demo
which makes finding the tar.gz file a cumbersome task.
The question is how can I make my bin-win target to move the file from there to a "better location"? (perhaps defined by an environment variable or a cmd line parameter/flag)
2- how can I include more files with my executable? My actual use case is I want to supply data files and some DLLs together with the executable. Should I use a filegroup() rule and refer its name in the "srcs" attribute as well?
2a- for the DLLs, is there a way to make a filegroup() rule to interpret environment variables? (e.g: the directories of the DLLs)
Thanks!
Look for the bazel-bin and bazel-genfiles directories in your workspace. These are actually junctions (directory symlinks) that Bazel updates after every build. If you bazel build //:demo, you can access its output as bazel-bin\demo.
(a) You can also set TMP and TEMP in your environment to point to e.g. c:\tmp. Bazel will pick those up instead of C:\Users\John\AppData\Local\Temp, so the full path for the output directory (that bazel-bin points to) will be c:\tmp\aS4O8v3V\execroot\__main__\bazel-out\x64_windows-fastbuild\bin.
(b) Or you can pass the --output_user_root startup flag, e.g. bazel--output_user_root=c:\tmp build //:demo. That will have the same effect as (a).
There's currently no way to get rid of the _bazel_John\aS4O8v3V\execroot part of the path.
Yes, I think you need to put those files in pkg_tar.srcs. Whether you use a filegroup() rule is irrelevant; filegroup just lets you group files together, so you can refer to the group by name, which is useful when you need to refer to the same files in multiple rules.
2.a. I don't think so.

Require dll using string path in F#

Is there a way to do this in F#:
let fakeToolsPath = "D:\tools\FAKE\tools\FakeLib.dll"
#r fakeToolsPath
the fake tools are on a different path depending on the build agent that builds the code, so I need to be able to set it dynamically, from an environment variable or some config file.
Three ideas, in order of increasing hackiness - you'll be the judge which one makes most sense in your scenario:
In .fsx script, you can use __SOURCE_DIRECTORY__ to get the directory where the script is located. If your dll is always located in the same directory relative to the script, you can use that as a "hook" to get to it.
There's a command-line --reference argument to fsi.exe that should do what you want. If you're using fake.exe instead, you can use --fsiargs to pass it in (take a look at the link for details).
If everything else fails, create a symlink as a separate build step in your CI job configuration and just hardcode the path in the script.

waf does not correctly detect C++ #include dependencies

I have C++ header file dependencies that I specify in my waf script with the includes=... parameter to bld.program().
I know the waf build configuration sees the includes because my program compiles correctly.
However, when I change a header file, waf does not detect the change. That is, when I run waf build after changing the contents of an included header, nothing gets recompiled.
Isn't waf supposed to determine #include "..." dependencies automatically?
How can I troubleshoot this?
I have looked in the build/c4che directory to see if I could make sense of the configuration files stored there. Mention of "include" in the waf generated .py files is suspiciously absent.
I am using waf version 1.9.0.
I have also tried this with waf 1.8.19 and got the same result.
EDIT: I replaced my original complicated wscript with the much simpler one listed below, and I still get the same behavior.
Here is my wscript:
top = '.'
out = 'build'
CXXFLAGS = ['-fopenmp', '-Wall', '-Werror', '-std=c++11', '-Wl,--no-as-needed']
def options(ctx):
ctx.load('compiler_cxx')
def configure(ctx):
ctx.load('compiler_cxx')
ctx.env.CXXFLAGS = CXXFLAGS
def build(ctx):
ctx.program(source="test_config_parser.cpp", target="test_config_parser", includes=["../include"], lib=['pthread', 'gomp'])
Your problem is that you use includes out of the project's directory. By default waf does not use external includes as dependencies (like system includes) to speed up things. Solutions I know of :
1/
Organize your project to have your include directory under the waf top directory :
top_dir/
wscript
include/
myinclude.h
sources/
mysource.cpp
2/
Change top directory. I think top = .. should work (not tested).
3/
Tell waf to go absolute by adding this lines at the beginning of build():
waflib.Tools.c_preproc.go_absolute=True
waflib.Tools.c_preproc.standard_includes=[]
4/
Use gcc dependencies by loading the gccdeps waf module.
Solution 1/ is probably the best.
By the way I prefer to have my build directory out of the source tree. Use out = ../build in your wscript, if you want to build out of the source tree.
my2c

Resources