My project is a C++ DLL (cmake project), that expose methods from a c interface to another C# project,
I want to add a methode getBuildTime() in the c interface that return the buildtime (the exact date and time) so from the C# project we can know when the DLL was built.
Is there a way to do this stuff ?
I don't know if this useful or no but I'm using git as a version control system
Build time in C/C++ code can be obtained by built-in macros __DATE__ and __TIME__, e.g. do something like string build_time = __DATE__ " " __TIME__;.
Also file which contains these macros usage needs to be touched before each build to change file's modify time. touch is a unix command, which can be avaialble in Windows too through Cygwin or other means. This is needed to force it to recompile to use new date. Do file touching by adding touch build_time.cpp command to Pre-Build Events, they should be located in your project config somewhere. Alternatively you may add touching to your make file. Altertnatively some compile environments and possibly MSVC too can configure which files to rebuild always which is tweaked inside project's settings.
Also if you use git version control system then you might want to use last git commit hash and time together or instead of build time above. Git commit hash and time is sometimes better than to use build time like suggested above, because git hash and time remain same on each re-compile before next commit, this ensures that your DLL build time changes only when code changes/committed, this may help to have reproducible DLL compiles. To support git hash and time do next things:
If you have unix echo and bash and git commands in your system e.g. by installing Cygwin or new native Windows SubSystem for Linux then you may do next things in command script before_build.cmd that you run before build, also this shell script can be run on Unix systems almost without modifications:
linux_echo -n "" > cfg.h
linux_echo -n "#define GIT_COMMIT """ >> cfg.h
linux_bash -c "echo -n $(git rev-parse --short=8 HEAD)" >> cfg.h
linux_echo """" >> cfg.h
linux_echo -n "#define GIT_COMMIT_TIME """ >> cfg.h
linux_bash -c "echo -n $(git show -s --format=%%ci $(git rev-parse --short=8 HEAD) | tr -d '\n')" >> cfg.h
linux_echo """" >> cfg.h
linux_echo -n "#define COMPILE_TIME """ >> cfg.h
linux_bash -c 'echo -n $(date +"%%Y-%%m-%%d %%H:%%M:%%S %%z")' >> cfg.h
linux_echo """" >> cfg.h
and you will get cfg.h like:
#define GIT_COMMIT "fe0a7891"
#define GIT_COMMIT_TIME "2020-05-13 17:42:55 +0100"
#define COMPILE_TIME "2020-05-13 18:20:28 +0100"
these config file and macros you can use in your code.
The C++ preprocessor predefines several macros (backward compatible with C) including __DATE__ and __TIME__. These expand to string literals containing the date and time of the build (in particular, the date and time that the preprocessor runs on that particular file).
You may need to force the compilation unit containing them to be rebuilt on every change. With make that can be done with .PHONY, with cmake it looks like add_custom_target is the ticket.
Add a target with no output so it will always be built.
Besides using __DATE__ and __TIME__ to capture when the compiler ran, the linker will store a timestamp in the PE header of the DLL it creates. There's no configuration necessary to make this happen, but then you have to write code to read the PE header and convert the timestamp to your favorite date and time format.
The preprocessor solution is way simpler, but the following approach may be convenient, if you need to provide other properties of the build system as well.
Create a cmake script file that generates a source file. Use this script to generate the source file providing the info:
generate_timestamp.cmake
#parameter: OUTPUT_FILE
string(TIMESTAMP _TIMESTAMP "%Y-%m-%dT%H:%M:%S")
file(WRITE ${OUTPUT_FILE} "#include \"buildtime.h\"
const char* getBuildTime() {
return \"${_TIMESTAMP}\";
}")
CMakeLists.txt
set(_BUILD_TIME_FILE buildtime.cpp)
add_library(mylib ${_BUILD_TIME_FILE} ...)
set_source_files_properties(${_BUILD_TIME_FILE} PROPERTIES GENERATED 1)
get_filename_component(_BUILD_TIME_FILE_ABSOLUTE ${_BUILD_TIME_FILE} ABSOLUTE)
# generate source using cmake script file
add_custom_target(buildtime_info COMMAND "${CMAKE_BUILD_TOOL}" -D "OUTPUT_FILE=${_BUILD_TIME_FILE_ABSOLUTE}" -P generate_timestamp.cmake)
# generate file before building mylib
add_dependencies(mylib buildtime_info)
Related
I have a build where it would be easiest for now to just have unique build rules for each build target (eg object file and library). Is it possible to specify in the build.ninja-file what to do without first specifying a rule for it.
For example (toy syntax)
build this_file: depends_on_this.o depends_on_that.o - gcc argumentss_to_use files.o etc
As usual I found out a way to do this a minute after asking.
We could just forward the whole command as a variable
rule run
command = $cmd
build log.txt: run
cmd = echo $hello >> log.txt
I have the following directory structure:
my_dir
|
--> src
| |
| --> foo.cc
| --> BUILD
|
--> WORKSPACE
|
--> bazel-out/ (symlink)
|
| ...
src/BUILD contains the following code:
cc_binary(
name = "foo",
srcs = ["foo.cc"]
)
The file foo.cc creates a file named bar.txt using the regular way with <fstream> utilities.
However, when I invoke Bazel with bazel run //src:foo the file bar.txt is created and placed in bazel-out/darwin-fastbuild/bin/src/foo.runfiles/foo/bar.txt instead of my_dir/src/bar.txt, where the original source is.
I tried adding an outs field to the foo rule, but Bazel complained that outs is not a recognized attribute for cc_binary.
I also thought of creating a filegroup rule, but there is no deps field where I can declare foo as a dependency for those files.
How can I make sure that the files generated by running the cc_binary rule are placed in my_dir/src/bar.txt instead of bazel-out/...?
Bazel doesn't allow you to modify the state of your workspace, by design.
The short answer is that you don't want the results of the past builds to modify the state of your workspace, hence potentially modifying the results of the future builds. It'll violate reproducibility if running Bazel multiple times on the same workspace results in different outputs.
Given your example: imagine calling bazel run //src:foo which inserts
#define true false
#define false true
at the top of the src/foo.cc. What happens if you call bazel run //src:foo again?
The long answer: https://docs.bazel.build/versions/master/rule-challenges.html#assumption-aim-for-correctness-throughput-ease-of-use-latency
Here's more information on the output directory: https://docs.bazel.build/versions/master/output_directories.html#documentation-of-the-current-bazel-output-directory-layout
There could be a workaround to use genrule. Below is an example that I use genrule to copy a file to the .git folder.
genrule(
name = "precommit",
srcs = glob(["git/**"]),
outs = ["precommit.txt"],
# folder contain this BUILD.bazel file is tool which will be symbol linked, we use cd -P to get to the physical path
cmd = "echo 'setup pre-commit.sh' > $(OUTS) && cd -P tools && ./path/to/your-script.sh",
local = 1, # required
)
If you're passing the name of the output file in when running, you can simply use absolute paths. To make this easier, you can use the realpath utility if you're in linux. If you're on a mac, it is included in brew install coreutils. Then running it looks something like:
bazel run my_app_dir:binary_target -- --output_file=`realpath relative/path/to.output
This has been discussed and explained in a Bazel issue. Recommendation is to use a tool external to Bazel:
As I understand the use-case, this is out-of-scope for building and in the scope of, perhaps, workspace configuration. What I'm sure of is that an external tool would be both easier and safer to write for this purpose, than to introduce such a deep design change to Bazel.
The tool would copy the files from the output tree into the source tree, and update a manifest file (also in the source tree) that lists the path-digest pairs. The sources and the manifest file would all be versioned. A genrule or a sh_test would depend on the file-generating genrules, as well as on this manifest file, and compare the file-generating genrules' outputs' digests (in the output tree) to those in the manifest file, and would fail if there's a mismatch. In that case the user would need to run the external tool, thus update the source tree and the manifest, then rerun the build, which is the same workflow as you described, except you'd run this tool instead of bazel regenerate-autogenerated-sources.
I have included a unix timestamp __DATE__ in one of my cpp source files to indicate the build date of my program. Naturally with default setups it compiles the file only when I change it but now I'd like to have it always compiled. I tried to search through the project settings but it seems that this would need deeper understanding of the compiler. I'm using Eclipse with g++.
I tried to google and search for an answer but I found it difficult to find good keywords for this.
Also is there a markable difference wether I do this change for a header file instead of the source file?
Thanks for the answers.
You may create a 'pre-build' step which touch the file (so the time stamp is modified and force to recompile the file).
it seems that this would need deeper understanding of the compiler.
No, it must be done by the build system.
A very simple-minded way of doing it is as follows. Create a single file called date.cpp with the following content and nothing else:
#include <string>
std::string build_time() {
return __DATE__ " " __TIME__;
}
You can use it like this in some other source file
cout << "Built on " << build_time() << endl;
The build system keeps track of your changes and it will only recompile those source files that have changed (that are necessary to be recompiled). Since you are not changing date.cpp file, it won't recompile it. However, you can force it by right clicking on the project folder and then
Properties > C/C++ Build > Settings > Build Steps > Post-build steps
and adding the following line to the comand field on Linux:
rm -f <path to the Debug / Release directory>/date.o
where you put yours to <path to the Debug / Release directory>.
On Windows del /q seems to do the same as rm -f, please check.
Since we delete the generated object file date.o, the build system must rebuild it again with the current build date and time when you compile the your application.
It's likely that there are many other variants but the above is in my opinion simple enough and does the trick.
My job mostly consists of engineering analysis, but I find myself distributing code more and more frequently among my colleagues. A big pain is that not every user is proficient in the intricacies of compiling source code, and I cannot distribute executables.
I've been working with C++ using Boost, and the problem is that I cannot request every sysadmin of every network to install the libraries. Instead, I want to distribute a single source file (or as few as possible) so that the user can g++ source.c -o program.
So, the question is: can you pack the Boost libraries with your code, and end up with a single file? I am talking about the Boost libraries which are "headers only" or "templates only".
As an inspiration, please look at the distribution of SQlite or the Lemon Parser Generator; the author amalgamates the stuff into a single source file which is trivial to compile.
Thank you.
Edit:
A related question in SO is for Windows environment. I work in Linux.
There is a utility that comes with boost called bcp, that can scan your source and extract any boost header files that are used from the boost source. I've setup a script that does this extraction into our source tree, so that we can package the source that we need along with our code. It will also copy the boost source files for a couple of boost libraries that we use that are no header only, which are then compiled directly into our applications.
This is done once, and then anybody who uses the code doesn't even need to know that it depends on boost. Here is what we use. It will also build bjam and bcp, if they haven't been build already.
#!/bin/sh
BOOST_SRC=.../boost_1_43_0
DEST_DIR=../src/boost
TOOLSET=
if ( test `uname` = "Darwin") then
TOOLSET="--toolset=darwin"
fi
# make bcp if necessary
if ( ! test -x $BOOST_SRC/dist/bin/bcp ) then
if ( test -x $BOOST_SRC/tools/jam/*/bin.*/bjam ) then
BJAM=$BOOST_SRC/tools/jam/*/bin.*/bjam
else
echo "### Building bjam"
pushd $BOOST_SRC/tools/jam
./build_dist.sh
popd
if ( test -x $BOOST_SRC/tools/jam/*/bin.*/bjam ) then
BJAM=$BOOST_SRC/tools/jam/*/bin.*/bjam
fi
fi
echo "BJAM: $BJAM"
pushd $BOOST_SRC/tools/bcp
echo "### Building bcp"
echo "$BJAM $TOOLSET"
$BJAM $TOOLSET
if [ $? == "0" ]; then
exit 1;
fi
popd
fi
if ( ! test -x $BOOST_SRC/dist/bin/bcp) then
echo "### Couldn't find bpc"
exit 1;
fi
mkdir -p $DEST_DIR
echo "### Copying boost source"
MAKEFILEAM=$DEST_DIR/libs/Makefile.am
rm $MAKEFILEAM
# Signals
# copy source libraries
mkdir -p $DEST_DIR/libs/signals/src
cp $BOOST_SRC/libs/signals/src/* $DEST_DIR/libs/signals/src/.
echo -n "boost_sources += " >> $MAKEFILEAM
for f in `ls $DEST_DIR/libs/signals/src | fgrep .cpp`; do
echo -n "boost/libs/signals/src/$f " >> $MAKEFILEAM
done
echo >> $MAKEFILEAM
echo "### Extracting boost includes"
$BOOST_SRC/dist/bin/bcp --scan --boost=$BOOST_SRC ../src/*/*.[Ch] ../src/boost/libs/*/src/*.cpp ../src/smart_assert/smart_assert/priv/fwd/*.hpp $DEST_DIR
if [ $? != "0" ]; then
echo "### bcp failed"
rm -rf $DEST_DIR
exit 1;
fi
Have you considered just writing a build script for a build system like SCons?
You could write a python script to download boost, unpack it compile the needed files (you can even run bjam if needed) and compile your own code.
The only dependency your colleagues will need is Python and SCons.
Run the preprocessor on your code and save the output. If you started with one main.cpp with a bunch of includes in it, you will end up with one file where all of the includes have been sucked in. If you have multiple cpp files, you will have to concatinate them together and then run the preprocessor on the concatinated file, this should work as long as you don't have any duplicate global symbol names.
For a more portable method, do what sqlite does and write your own script to just combine and concatinate together the files you created+boost, and not get the system includes. See mksqlite3c.tcl in the sqlite code
http://www2.sqlite.org/src/finfo?name=tool/mksqlite3c.tcl
Why not just check in all the necessary files to SVN, and send you co-workers the URL of the repository? Then they can check out the code whenever they want to, do an 'svn up' any time they want to update to the latest version, etc.
If you're on a Debian-derived variety of Linux, well problems like this just shouldn't come up: let the packaging system and policy manual do the work. Just make it clear that the libboost-dev or whatever package is a build-dependency of your code and needs to be installed beforehand, and then /usr/include/boost should be right there where your code expects to find it. If you're using a more recent version of boost than the distro ships, it's probably worth figuring out how to package it yourself and work within the existing packaging/dependencies framework rather than reinventing another one.
I'm not familiar enough with .rpm based distros to comment on how things work there. But knowing I can easily setup exactly the build environment I need is, for me, one of the biggest advantages of Debian based development over Windows.
I would like to have a variable (or #define) in C++ source that will increment each time I use Qt Creator to build source code. Is there any way I can do this, perhaps some Qt Creator plugin or similar? If there is a way to do it if I use "make" on command line to build?
In your .pro file, you can create a variable that contains the results of a command-line program. You can then use that to create a define.
BUILDNO = $$(command_to_get_the_build_number)
DEFINES += BUILD=$${BUILDNO}
If you just want a simple incrementing number, you could use a pretty simple script:
#!/bin/bash
number=`cat build_number`
let number += 1
echo "$number" | tee build_number #<-- output and save the number back to file
I should note that this would cause the build number to increment every time you build, and also increment if you try to build but it fails. A better way is to get a build number based on the state of the code, and many version control tools can get you a text string for that, if not a number.
The Windows equivalent for Joerg Beutel's improved solution https://stackoverflow.com/a/5967447/1619432:
.pro:
build_nr.commands = build_inc.bat
build_nr.depends = FORCE
QMAKE_EXTRA_TARGETS += build_nr
PRE_TARGETDEPS += build_nr
HEADERS += build.h
build_inc.bat:
#echo off
set /p var= <build.txt
set /a var= %var%+1
echo %var% >build.txt
echo #define BUILD %var% >build.h
echo %var%
Usage
#include "build.h"
...
qDebug() << "Build number:" << BUILD;
As I wrote before after some testing I found that the original solution has a problem since the version number is not updated every time a new build is done. In a lot of cases I had edited a source file, run the build, but still got the same build number ... The building process just decided that nothing was changed and skipped the step which would have updated the build number. I first attempted to find a way to force that step, but couldn't figure it out. Finally I decided to go a different way. Now I use the script to generate a header file
build_number.h which contains a #define BUILD with the updated number behind. So Calebs script is now a bit modified (build_number.sh) :
#!/bin/bash
number=`cat build_number`
let number++
echo "$number" | tee build_number #<-- output and save the number back to file
echo "#define BUILD ""$number" | tee ../MyProject/build_number.h
The incrementing number is still stored within a file called build_number. I could have avoided a third file by parsing the generated header-file for the number, but decided against it. Note that the script and the generated header are located in the projects directory while the build_number file is in the build directory. That's not perfect, but I can live with it.
In order to put things together there are now some more things to do. First the generated header-file needs to be added to the project in the Qt Designer ... Right-click on Header-Files and "Add existing file". Second, it has to be included in the C++-file where the BUILD define inside is accessed ... #include "build_number.h" ... and last but not least some additions have to be made to the project file (MyProject.pro). Note that I deleted the stuff from Calebs solution, so we start from scratch here :
build_nr.commands = ../MyProject/build_number.sh
build_nr.depends = FORCE
QMAKE_EXTRA_TARGETS += build_nr
PRE_TARGETDEPS += build_nr
These lines (I put them before the HEADERS section) force the execution of the script, which reads the last build number from build_number, increments it, writes it back and also generates an updated version of the build_number.h file. Since that's part of the source of the project the new value gets linked into the code every time.
There's one thing to mention - now the building process is never at the opinion that nothing has changed. So even if you leave your code unchanged a new run of make will generate a new version number and build a new binary. The old solution left the number when code changed, this new solution forces a new build even when the source is unchanged, since I force a change in that one header file. One would have prefered something in between but since the header is only included in one place the rebuild is very fast and doesn't hurt much. But still, if somebody knows how to get the best of both worlds please advise. At least now I'll not have two different binaries with the same version number.
Caleb's suggestion is great, but didn't work "out of the box" in my case. I got some errors instead and it took some reading to fix them. The changes are very minor. I was using Qt 4.7 on Ubuntu Linux ... The first change, if you can believe it, was in the shell script to go from let number += 1 to let number++ ... I normally use/program Windoze, so I can't explain that, but when I run the script from a command line (shell prompt) in the original case I get errors reported, in the changed case all goes well and incrementing numbers are returned ...
Since it's not completely reported by Caleb - I used build_number.sh as the name of the shell script and made another file with the name build_number (without .sh) and put just a zero inside, nothing else.
The last and most obnoxious bug was fixed by replacing BUILDNO = $$(command_to_get_the_build_number) with BUILDNO = $$system(./build_number.sh) in the Qt project file. Note the system after $$ and the required ./ in front of the file name. The later is elementary for a regular Linux user, but not as much so for a Windows user.
Hope this makes it more straight forward for people new to all this, like myself. You can read more in the Qt Designer Help section if you seek for qmake, including the function reference, Advanced Use etc.
Oh, one last word ... I also had to change DEFINES += -DBUILD=$${BUILDNO} to DEFINES += BUILD=$${BUILDNO}, so the -D is gone. Inside your C++ code you would use BUILD as if you had written #define BUILD 1234 at the top of your file.
Here's a solution for Win7 I came up with based on handle's solution.
This solution also makes Windows give yer version # when you right-click yer target, and choose Properties | Details. It works in Win7, and probably most earlier versions.
Ok, you make yer build_inc.bat:
#echo off
copy /b myapp.rc +,,
set /p var= <build.txt
set /a var= %var%+1
echo %var% >build.txt
echo #define BUILD %var% >build.h
and put it in yer proj folder. (copy /b myapp.rc +,, is inscrutable Microsoft-eese for "touch" - to update a file's time-stamp.) So far, so good - so what?!!
This part is optional, if you don't need the version encoded into the binary. Create a .rc file, e.g.:
#include "build.h"
1 VERSIONINFO
FILEFLAGS 32
FILEVERSION 1, 0, BUILD, 0
PRODUCTVERSION 1, 0, BUILD, 0
FILEOS 4
FILETYPE 1
{
BLOCK "StringFileInfo"
{
BLOCK "040904B0"
{
VALUE "FileDescription", "program"
VALUE "OriginalFilename", "program.exe"
VALUE "CompanyName", "you"
VALUE "FileVersion", "Release"
VALUE "LegalCopyright", "Copyright (c) 2016, you, fool!"
VALUE "ProductName", "Yer proggie"
VALUE "ProductVersion", "Release"
}
}
BLOCK "VarFileInfo"
{
VALUE "Translation", 0x0409, 0x04B0
}
}
A more full-blown version is available here: Versioning DLLs. BTW: It won't work without the VarFileInfo block. This .rc is used for stuff like right-clicking and getting this info in Properties | Details. I have both a M$ .rc file for this info and the app icon, and add other resources in Qt Creator under Resources.
Not so optional: Here's the part I've spent some time hacking to find. In Qt Creator, with yer proj opened, click the little computer icon and put it in release mode. Click on "Projects". Click on "Add Build Step", choose Custom Process Step, and click the hat icon "^" until it is at the top of the list. Say you've named yer .rc, "myapp.rc". Make tha build step read as follows:
Command: cmd.exe
Arguments:/c build_inc.bat
Working Directory: %{CurrentProject:Path}
While a qmake-based version might work well from the command line or command line tools called from an IDE, in Qt Creator, the build steps are preferable, I believe. Qt Creator doesn't actually run qmake for each build; but build steps are run every build.
Now, add this to yer .pro file:
RC_FILE += myapp.rc
Also, add myapp.rc to yer proj. It'll show up under "Other Files".
Now rebuild. Every rebuild will trigger a touch of the resource file, thereby running "rc" every time. Otherwise, the build number won't get encoded into the binary right. It runs quickly for me. Every rebuild will increment this number. I've only bothered to add them to the "Release" build; so debug builds don't increment this. They'll just use the number of the last build. You will need to run it once in release to avoid an error, I believe. This works without separately re-running qmake each time in Qt Creator; and gives you a different build number each time. It doesn't trigger any other recompiles. You have the overhead of running "rc" and linking each time, as opposed to doing nothing if everything is up to date; but OTOH, I do it for release builds only; you almost always link for a build or run anyway; and again, "rc" is fast.
Optional: You can move the BUILD preprocessor symbol wherever you want in yer vers. #. (Note: You can also add yer app icon with something like this:
IDI_ICON1 ICON DISCARDABLE "Icons/myicon.ico"
This makes it show up in Explorer even before the file is run.)
You can also add "build.h" to yer proj formally in Qt Creator, include it in a file you want to use the build # in, and use it as a string, e.g. with:
#include <QDebug>
#include "build.h"
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
qDebug() << QString("(build ")+STR(BUILD)+")";
I just noticed a side effect: If you do it this way, it will rebuild before every run in Release. I guess that's not too bad a price to pay. I guess I can always copy the runtimes into the release directory, and run it from Explorer; or just put up with the extra compile of my about.h, the run of "rc" and the link with each run in release. For that matter, I could just create an external tool to run it with a keyboard shortcut. I'm certainly open to any improvements on this. For the time being, I'm not bothering, as just compiling "about.cpp", running "rc" and linking with every run doesn't take very long. Still, people: automatic build numbers!
☮!
Edit: Optional: In order to get it to increment the build number only when you build or rebuild your project, but not when you run it (even though a build will always occur in Release), go to Projects | Build and Run | Run, click "Add a Deploy Step" and choose "Custom Process Step":
Command: cmd.exe
Arguments: /c if exist build.old copy /y build.old build.txt
Working Directory: %{CurrentProject:Path}
Then, add
copy /y build.txt build.old
after #echo off in the .bat file. It is even possible, although involved, to make custom new project templates: Extending Qt Creator Manual
Edit: I've now made it work with one, not two, custom build steps.