External configuration of Project_Version in gpr file - ada

With gnatpro 19.1, I'm trying to add gnathub to my project and am wondering how to set dynamically Project_Version as in:
package Dashboard is
for Project_Version use #git --describe --tags#; -- this needs to be updated.
end Dashboard;
I can't think of any simple way to do it.
A solution would be to use a Makefile that would configure a .gpr.in file but it seems contrived to change my whole buildchain just to add a version to the sonar config.
A simple, not automated solution, is to call the project with another switch:
gnathub -P Foo.gpr --plugins sonar-config,sonar-scanner\
--targs:sonar-scanner -Dsonar.projectVersion=$(git describe --tags)
But this is not really usable.
Similar question is to add the option -Dsonar.branch.name=$(git branch). AFAICT, the package Dashboard, as per the documentation has no Switch switch.
Is there any solution other than passing the extra arguments or forking gnatdashboard?

The best solution seems to reside in automating this configuration with a tool like Make.
For example, one can define the following Makefile:
# This target runs all the plugins listed
# in the section Dashboard.plugins of your project’s gpr
# sonar-config and sonar-scanner shall not be listed therein.
analyzes:
gnathub -P project
# This uses gnathub API to get the object dir where sonar-config file will be generated
OBJECT_DIR = $(shell gnathub -P project --exec object_dir.py 2>/dev/null | tail -n 1)
SONAR_PROPERTIES = $(OBJECT_DIR)/gnathub/sonar/sonar-project.properties
PROJECT_VERSION = $(shell git describe --tags)
BRANCH_NAME = $(shell git rev-parse --abbrev-ref HEAD)
# Uses gnathub to generate sonar properties file.
# Replaces the projectVersion and add branch name
# (notice that, on sonar, the branch name shall not be specified on your "master" branch)
$(SONAR_PROPERTIES): analyzes
gnathub -P project --plugins sonar-config --incremental
#sed -i "s/\(sonar.projectVersion = \).*/\1$(PROJECT_VERSION)/" $#
ifneq ($(BRANCH_NAME), master)
#echo "sonar.branch.name = $(BRANCH_NAME)" >> $#
endif
sonar: $(SONAR_PROPERTIES)
gnathub -P project --plugins sonar-scanner --incremental
.PHONY: sonar analyzes
Where object_dir.py is:
#!/usr/bin/env python
import GNAThub;
print (GNAThub.Project.object_dir());
Then:
$make sonar
Would run the analyzes and update them with the correct version and branch name (if necessary) to the SonarQube server.

Related

Creating Fat Jars: What is the mods folder?

I'm just on:
https://openjfx.io/openjfx-docs/#modular
trying to create a jar I can run on other systems (that do not have the javafx libraries as would happen with a non-developer layman user) and they've told me to use this:
dir /s /b src\*.java > sources.txt & javac --module-path %PATH_TO_FX% -d mods/hellofx #sources.txt & del sources.txt
What is mods/
Where is that supposed to be? Are they talking about out/ ?
The doc you have linked refers to this sample.
If you clone the sample, and follow instructions on how to compile and run the project, the first command can be divided in three parts:
dir /s /b src\*.java > sources.txt & \
javac --module-path %PATH_TO_FX% -d mods/hellofx #sources.txt & \
del sources.txt
The first part just gets all the Java files in the src path and adds that to sources.txt file:
C:\path\to\hellofx\src\module-info.java
C:\path\to\hellofx\src\hellofx\HelloFX.java
The second part calls the javac command (see reference) to compile the content of sources.txt, adding the required --module-path option to include the JavaFX modules, and also adding the output or destination -d option:
-d directory
Sets the destination directory for class files. If a class is part of a package, then javac puts the class file in a subdirectory that reflects the package name and creates directories as needed.
This means that we are going to compile hellofx.HelloFX.java into the directory mods/hellofx, resulting in:
C:\path\to\hellofx\mods\hellofx\module-info.class
C:\path\to\hellofx\mods\hellofx\hellofx\HelloFX.class
The third step will just remove the sources.txt file.
And now you can run your module:
java --module-path "%PATH_TO_FX%;mods" -m hellofx/hellofx.HelloFX
You can specify any directory for the output, of course, so you can change it to out or build for instance, but then make sure you modify it accordingly in the rest of the instructions.

How to use existing QMake project (.pro project file) as "external project" in CMake?

Is there a concise doc or example for how to use an existing QMake project with .pro project file as an "external project" in CMake? This can somewhat be done in qtcreator by marking one project as dependency of another, but it would be nice to define it more explicitly with the ExternalProject() CMake syntax.
related question: CMake: How to build external projects and include their targets
Something like this works. You can then edit the files from either qtcreator in main CMake project tree, OR from opening the .pro file; great for iterating quickly on QT widgets in SomeGarbageApplication that is part of large cmake build tree.
macro(DeclareProjectFiles Tag Filez)
######### Trick: use this syntax to make arbitrary files
######### appear in IDE project. #######################
### Note: pass in the raw name of a list variable,
### since it will get expanded here in this macro.
add_custom_target(${Tag}_files ALL
pwd
COMMAND ls -ltrh
COMMENT " ${Tag} files thunk... got list: [ ${${Filez}} ]"
VERBATIM
SOURCES ${${Filez}}
)
endmacro()
message(STATUS "QT_QMAKE_EXE is: ${QT_QMAKE_EXECUTABLE}")
set(Z SomeGarbageApplication)
file(GLOB ${Z}_Files
./*.cpp
./*.h
./*.ui
./*.pro
./*.png
./*.jpg)
DeclareProjectFiles( ${Z}_grbg ${Z}_Files )
add_custom_target(${Z}_pro ALL)
set(ExtraQMakeArgs -r -spec linux-g++ CONFIG+=release)
# note: use killall because this can/will fail if the exe is running
# But, need || true to not fail build when it's not running.
add_custom_command(TARGET ${Z}_pro
COMMAND killall
ARGS -q -9 -v ${Z} || true
COMMAND ${QT_QMAKE_EXECUTABLE}
ARGS -query
COMMAND ${QT_QMAKE_EXECUTABLE}
ARGS ${CMAKE_CURRENT_SOURCE_DIR}/${Z}.pro ${ExtraQMakeArgs}
COMMAND make ${Z}
ARGS -j4
COMMAND cp
ARGS ${Z} ${CMAKE_CURRENT_SOURCE_DIR}/${${Z}_config} ${CMAKE_BINARY_DIR}/bin/
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
VERBATIM
)
#################################################################

Create a custom symbolic link to a library at install time with CMake

Under Linux with CMake, I'm building a shared library libIex-2_0.so.10.0.1
ADD_LIBRARY (Iex SHARED
[*.cpp]
)
SET_TARGET_PROPERTIES(Iex PROPERTIES OUTPUT_NAME "Iex-2_0")
The 10.0.1 version is set with a call to
SET_TARGET_PROPERTIES ( Iex
PROPERTIES
VERSION 10.0.1
SOVERSION 10
)
In the installation folder, these links are created
libIex-2_0.so -> libIex-2_0.so.10
libIex-2_0.so.10 -> libIex-2_0.so.10.0.1
libIex-2_0.so.10.0.1
However, to match previous builds made with another build system, I need to add a legacy symbolic link, stripping the 2_0 suffix :
libIex.so -> libIex-2_0.so.10.0.1
What would be the proper CMake way to create such a link ?
One way to do it could be using CMake add_custom_command and add_custom_target. In your case it would be something like the following:
SET( legacy_link ${CMAKE_INSTALL_PREFIX}/libIex.so)
SET( legacy_target ${CMAKE_INSTALL_PREFIX}/libIex-2_0.so.10.0.1)
ADD_CUSTOM_COMMAND( OUTPUT ${legacy_link}
COMMAND ln -s ${legacy_target} ${legacy_link}
DEPENDS install ${legacy_target}
COMMENT "Generating legacy symbolic link")
ADD_CUSTOM_TARGET( install_legacy DEPENDS ${legacy_link} )
At this point you should have a target install_legacy in your generated Makefile with the correct dependency to generate libIex.so.
Another way is to run some install(CODE shell-script). It does correctly attach to the general "make install" target by the way. With better control on the working_directory it is also possible to create relative symlinks easily.
I did also require that make install DESTDIR=/buildroot works and for that it is required to leave $DESTDIR unexpanded until the shell-script is invoked. Along with some magic for portability it looks like this:
get_target_property(libname MyLib OUTPUT_NAME)
get_target_property(libversion MyLib VERSION)
set(lib ${CMAKE_SHARED_LIBRARY_PREFIX})
set(dll ${CMAKE_SHARED_LIBRARY_SUFFIX})
install(CODE "execute_process(
COMMAND bash -c \"set -e
cd $DESTDIR/${CMAKE_INSTALL_PREFIX}/${CMAKE_INSTALL_LIBDIR}
echo -n .. Installing: `pwd`
ln -sv ${lib}${libname}${dll}.${libversion} ${lib}${libname}${dll}.11
echo -n .. Installing: `pwd`
ln -sv ${lib}${libname}${dll}.${libversion} ${lib}${libname}${dll}.12
\")")
P.S. assuming include ( GNUInstallDirs ) here.

makefile with directory tree creation suitable for parallel (-j ) build

My project needs temporary directories which are created during the build using mkdir -p similarly to this:
all: dirtree $(OBJFILES)
dirtree:
#mkdir -p $(BUILD)/temp_directory
But this approach cannot be used with the -j switch, because first of the OBJFILES get compiled before the mkdir target is made.
Is there a standard way to do this?
The problem with your makefile is that creation of your object files does not depend on creation of the relevant directories (only a phony "all" target does). This kind of dependency is necessary for -j option, and even without it your makefile works only by chance. There are two (right) ways to impose the dependency in question.
Directories as separate targets
You created the target for directory creation; what left is just put it as a prerequisite to object file rule:
$(BUILD)/temp_directory/%.o: %.c | dirtree
$(CC) $^ -o $#
The pipe symbol | means that dirtree is an "order only prerequisite". It is used when "dirtree" is a prerequisite but changes in the dirtree do not invalidate object files and do not affect the outcome of compilation command.
Use of "order-only" prerequisite is important here. The thing is that dirtree target would be remade at each Make invocation. That would cause everything that depends on it be remade as well, so it would rebuild all object files every time.
Create directories in shell commands
Another way is to ensure that the directory is created immediately before you invoke compilation
$(BUILD)/temp_directory/%.o: %.c
#mkdir -p $(#D)
$(CC) $^ -o $#
Note the usage of $(#D). This is expanded as "the directory for the target file". So it may be used uniformly in many places, and even with aid of a variable.
Mkdir=#mkdir -p $(#D)
$(BUILD)/temp_directory/%.o: %.c
$(Mkdir)
$(CC) $^ -o $#
$(INSTALL_DIR)/%: src_dir/%
$(Mkdir)
cp -p $^ $#
Both ways ensure that the directory is created before the compilation commands are invoked. Both ways require you to write some text (either | dirtree or $(Mkdir)) at each rule that needs it. Both ways are -j compatible, but the second solution requires mkdir -p to be thread-safe (as two such commands at once may try to create the same directory, and one of them would fail).
While most systems implement it in such a way that mkdir -p is more or less thread safe, on some systems (as in some Solaris systems, for example), they are less thread-safe than the others. However, even in GNU toolchain mkdir -p may fail if they simultaneously invoke the same mkdir(2) library call.
If you want to be very safe, you can work this around as well. What could be the problem? That two mkdir -p scripts try to create the same directory, and clash somewhere inside C library. Then, one of these mkdir-s will succeed, and the other will fail. However, if the mkdir you invoked failed, then it could be thread-unsafety-related failure only if the directory had been created by a concurrent mkdir. So it would be enough to just check that the target directory is created after mkdir invocation:
Mkdir=#mkdir -p $(#D) || test -d $(#D)
(This solution also has an issue with mode: mkdir may fail when directory exists, but doesn't conform to umask, so you might want to check that as well. But that's too much I guess.)
I'm not sure I fully understand your question. However, I can say this: if your build breaks when you add parallelism, then it's an indication that you haven't defined the dependencies correctly. Ask yourself, "Do the directories need to exist before the object files are generated?" If the answer is "yes", then the directories should be listed as prerequisites of the object files. In other words:
${OBJFILES}: dirtree
And yes, that is pretty much the standard way to do this :)
You could have the rules for building the object files call mkdir -p as their first action.

Call cmake from make to create Makefiles?

I am using cmake to build my project. For UNIX, I would like to type make from my project's root directory, and have cmake invoked to create the proper Makefiles (if they don't exist yet) and then build my project. I would like the cmake "internal" files (object files, cmake internal Makefiles, etc.) to be hidden (e.g. put in a .build directory) so it doesn't clutter my project directory.
My project has several sub-projects (in particular, a library, a user executable, and a unit test executable). I would like Makefiles (i.e. I type make and this happens) for each sub-project to execute cmake (as above) and build only that sub-project (with dependencies, so the library would be built from the executables' Makefiles, if needed). The resulting binary (.so library or executable) should be in the sub-project's directory.
I made a Makefile which does the main project bit somewhat well, though it feels somewhat hackish. I can't build specific targets using it, because my Makefile simply calls make in cmake's build directory.
Note that because the library is a sole dependency (and probably doesn't need to be build manually, and because I'm lazy) I omitted it in my Makefile.
BUILD_DIR := .build
.PHONY: all clean project-gui ${BUILD_DIR}/Makefile
all: project-gui project-test
clean:
#([ -d ${BUILD_DIR} ] && make -C ${BUILD_DIR} clean && rm -r ${BUILD_DIR}) || echo Nothing to clean
project-gui: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-gui
#cp ${BUILD_DIR}/project-gui/project-gui $#
project-test: ${BUILD_DIR}/Makefile
#make -C ${BUILD_DIR} project-test
#cp ${BUILD_DIR}/project-test/project-test $#
${BUILD_DIR}/Makefile:
#[ -d ${BUILD_DIR} ] || mkdir -p ${BUILD_DIR}
#[ -f ${BUILD_DIR}/Makefile ] || (cd ${BUILD_DIR} && cmake ${CMAKE_OPTS} ..)
If it helps, here's my project structure (if this is "wrong" please tell me -- I'm still learning cmake):
project/
project/CMakeLists.txt
project/common.cmake
project/Makefile -- see Makefile above for this; should be replaced with something better, building libproject, project-gui, and project-test
project/libproject/
project/libproject/CMakeLists.txt
project/libproject/libproject.so -- after build
project/libproject/Makefile -- doesn't exist yet; should build libproject only
project/libproject/source/
project/libproject/include/
project/project-gui/
project/project-gui/CMakeLists.txt
project/project-gui/Makefile -- doesn't exist yet; should build libproject then project-gui
project/project-gui/source/
project/project-gui/include/
project/project-test/
project/project-test/CMakeLists.txt
project/project-test/Makefile -- doesn't exist yet; should build libproject then project-test
project/project-test/source/
project/project-test/include/
If you haven't caught on yet, I'm basically looking for a way to build the project and sub-projects as if cmake wasn't there: as if my project consisted of only Makefiles. Can this be done? Is the solution elegant, or messy? Should I be trying to do something else instead?
Thanks!
If cmake is generating the makefiles, you can simply include the generated makefile in the master makefile, eg
# makefile
all: # Default
include $GENERATED
$GENERATED:$CMAKEFILE
# Generate the makefile here`
The included files are generated then make is restarted with the new included files. The included files should detail the targets, etc.
You should be able to change the location of used files using the vpath directive, see e.g. the Gnu make manual,
vpath %.o project/.build
else the tedious way is to rewrite the rules making note of the necessary directory.
Ed:
Perhaps we shouldn't use a flat makefile.
Try something like:
# makefile
all: gui test
clean:
$(MAKE) -f $(GUI-MAKE) clean
$(MAKE) -f $(TEST-MAKE) clean
gui:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) all
$(GUI-MAKE):$(GUI-CMAKE)
# Generate
# Same for test
This should work if the $(MAKE) -f $(GUI-MAKE) all command works on the command line, and we've hidden cmake in the generating target. You would have to copy any other targets to the master makefile as well, and take care running make in parallel.
Propagating object files through should involve something like
%.o:$(GUI-MAKE)
$(MAKE) -f $(GUI-MAKE) $#
although you'll probably get errors trying to make test objects

Resources