Use msbuild on solution to call custom target on some projects - c++

I've been trying to figure out a proper way of leveraging the information already present in a solution file of a rather big c++ code base.
The problem I'm trying to solve is calling an external script on some of the project files within the solution, but observing the already present dependencies specified in the solution and single project files.
I've successfully called said (python) script by adding a custom target to one of my project files and using msbuild with the /t:{TargetName} command on the vcxproj file.
I could now add this target to every project file that needs to call this script and afterwards call msbuild for each of them in the correct order, however this defeats the purpose of leveraging the dependencies known by the solution.
Calling the solution with the custom target does however not work (as seen by other stackoverflow questions like this: Invoke Custom MSBuild Target on Solution File).
On the other hand, since I want to be able to ONLY call the script target and not being dependent on also calling some Build command, I cannot use the proposed workarounds in some of those answers of adding a Post or PreBuild target.
Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?

Is there any other way of using the dependencies without having to go the route of msbuild and custom targets, or is there an other workaround that could serve my purpose?
You can build the sln programmatically, Here is a console APP with c# for your reference.
using Microsoft.Build.Construction;
using Microsoft.Build.Evaluation;
using Microsoft.Build.Framework;
using Microsoft.Build.Logging;
using System;
namespace LoadAllProject
{
class Program
{
static void Main(string[] args)
{
ILogger logger = new ConsoleLogger();
string solutionPath = #"D:\Project\Msbuild\CppApp5\CppApp5.sln";
var solutionFile = SolutionFile.Parse(solutionPath);
foreach (var item in solutionFile.ProjectsInOrder)
{
Project project = ProjectCollection.GlobalProjectCollection.LoadProject(item.AbsolutePath);
project.SetGlobalProperty("Configuration", "Debug");
if (project.GetPropertyValue("RootNamespace") == "CppApp5")
{
project.Build(new[] { "Build", "Yourcustomtarget" }, new[] { logger });
}
else
{
project.Build(new[] { "Build" }, new[] { logger });
}
}
Console.ReadKey();
}
}
}

Related

How to run a c++ function using MSBuild targets?

I am using MSBuild and I came across this topic called Targets that lets you perform some tasks before building the project.
I need to run a C++ function which is present in a .cpp file in my (.sln) solution file. I came across this example to run a task, but it is written in C#.
using System;
using Microsoft.Build.Utilities;
namespace SimpleTask1
{
public class SimpleTask1: Task
{
public override bool Execute()
{
// This is where the task would presumably do its work.
return true;
}
}
}
So basically, I want run a C++ function before the building my solution file and I am confused on how to use MSBuild tasks and targets for this purpose. This C++ function actually generates some code that is necessary for successful building, else the build would fail.

QBS build system, can't initialize environment with vcvars64.bat

I'm trying to implement my own module to build C++ on Windows with clang-cl toolchain as there's no built-in support in QBS right now.
I chose to use lld-link instead of microsoft linker, so I have to supply it with all the MS library include paths manually. With these paths hardcoded, I manage to build my apps fine. But I'd like to make my module more flexible and use %LIB% environment variable set by vcvars32.bat|vcvars64.bat
As far as I understand, this could (should?) be done inside module's setupBuildEnvironment script. Here's what I try to read the %LIB% and fail:
import qbs.Environment
import qbs.Process
Module
{
setupBuildEnvironment:
{
var p = new Process();
p.exec("vcvars64.bat", [], true);
// makes no difference
// p.exec("cmd", ["/c", "vcvars64.bat"], true);
var lib = p.getEnv("LIB");
// this fails too
// var lib = Environment.getEnv("LIB");
console.info("LIB = " + lib);
p.close();
}
...
}
This gives me LIB = so I'm getting nowhere. My guess is that the process is already terminated at the moment of querying the variable (p.getEnv("LIB")), hence the empty result. The QBS docs for Process.getEnv() state nothing in this regard.
What is the correct QBS way to initialize environment with vcvars64.bat, and more broadly, what is the correct way to get environment of a process inside setupBuildEnvironment?
[update]
Well, embarassingly, this was easy to work around by creating a simple batch and getting rid of setupBuildEnvironment script altogether:
#echo off
call vcvars64 && qbs
But I'd like to avoid batch scripting as much as possible, so the question still stands.
The vars batch files just dump some information onto the console. That does not set an environment on the calling process in any way. You would need to parse the process output. I suggest you take a look at the MsvcProbe item in the qbs sources to see how that is implemented for MSVC. You might be able to adapt the code for clang-cl.

How do I add MinGW Kotlin Native dependencies

I'm trying to create a small application that will be able to communicate with the AWS IoT service. Since I want it to be fairly small and I wanted to try something new, I decided to go for Kotlin Native. I quickly noticed that AWS has released their C++ library that allows you to easily connect to the AWS IoT service (https://github.com/aws/aws-iot-device-sdk-cpp/tree/release) I downloaded it and even managed to compile with MinGW (yes, I'm on Windows). I noticed that it generated a bunch of *.o files. I reckon this is now the right time to import it to my Kotlin Native project. My build.gradle file for now looks completely standard
plugins {
id 'kotlin-multiplatform' version '1.3.11'
}
repositories {
mavenCentral()
}
kotlin {
targets {
// For ARM, preset should be changed to presets.iosArm32 or presets.iosArm64
// For Linux, preset should be changed to e.g. presets.linuxX64
// For MacOS, preset should be changed to e.g. presets.macosX64
fromPreset(presets.mingwX64, 'mingw')
configure([mingw]) {
// Comment to generate Kotlin/Native library (KLIB) instead of executable file:
compilations.main.outputKinds('EXECUTABLE')
// Change to specify fully qualified name of your application's entry point:
compilations.main.entryPoint = 'sample.main'
}
}
sourceSets {
// Note: To enable common source sets please comment out 'kotlin.import.noCommonSourceSets' property
// in gradle.properties file and re-import your project in IDE.
mingwMain {
}
mingwTest {
}
}
}
task runProgram {
def buildType = 'release' // Change to 'debug' to run application with debug symbols.
dependsOn "link${buildType.capitalize()}ExecutableMingw"
doLast {
def programFile = kotlin.targets.mingw.compilations.main.getBinary('EXECUTABLE', buildType)
exec {
executable programFile
args ''
}
}
}
for some reason I cannot find any examples as to how to add my freshly complied dependency. Normally when you code C++ you have to specify the path to Include directory and the Lib directory separately. AFAIK this is not something that gradle provides out of the box. How can I import this dependency then? Or perhaps there's some centralised repository I could simply pull such dependency from, like in pretty much every other programming language that is still used nowadays? At least this specific library doesn't seem to be available on NuGet :/
Kotlin/Native is not[1] interoperable with C++ at this moment. You can however create C wrapper for any C++ library and it's functions from Kotlin/Native[2].
When using multiplatform gradle plugin you can define native interop with this syntax:
kotlin {
linuxX64 { // Replace with a target you need.
compilations.main {
cinterops {
myInterop {
// Def-file describing the native API.
// The default path is src/nativeInterop/cinterop/<interop-name>.def
defFile project.file("def-file.def")
// Package to place the Kotlin API generated.
packageName 'org.sample'
// Options to be passed to compiler by cinterop tool.
compilerOpts '-Ipath/to/headers'
// Directories for header search (an analogue of the -I<path> compiler option).
includeDirs.allHeaders("path1", "path2")
// Additional directories to search headers listed in the 'headerFilter' def-file option.
// -headerFilterAdditionalSearchPrefix command line option analogue.
includeDirs.headerFilterOnly("path1", "path2")
// A shortcut for includeDirs.allHeaders.
includeDirs("include/directory", "another/directory")
}
anotherInterop { /* ... */ }
}
}
}
}
If you only define the interop name the plugin will look for .def file[3] in src/nativeInterop/cinterop/ directory and use it (in this case src/nativeInterop/cinterop/myInterop.def).
kotlin {
linuxX64 {
compilations.main {
cinterops {
myInterop {
}
}
}
}
}
The .def files[3] contains information about the library you are trying to use and typically look like this.
headers = png.h
headerFilter = png.h
package = png
More information about cinterop: https://kotlinlang.org/docs/reference/native/c_interop.html
More information about multiplatform projects: https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html

Force rcc-ing of qrc file on each build

How to force rcc-ing of a qrc file on each build in Visual Studio 2015? We are embedding the resources in the binary, so if something like qml or image assets change, we need to run rcc to get a fresh .cpp file for the current state. I see several options - brutally touching the .qrc file in a pre build event, running a script which checks everything in the asset folder before build and checking the timestamps and comparing them to a state at the previous build. Are there cleaner and more elegant options?
If you were to use CMake, you could add a pre-build task to delete the your-project-name_autogen folder from the build directory. This forces CMake to rcc the qrc file each build.
The command might look something like:
add_custom_command (TARGET your-project-name PRE_BUILD
COMMAND ${CMAKE_COMMAND} -E remove_directory ${CMAKE_BINARY_DIR}/your-project-name_autogen)
CMake does this by adding a Pre-Build Event to its generated Visual Studio project, so you can also replicate it with only Visual Studio. If you haven't found the pre-build event section already, right-click on the desired project (not solution), and select Properties. Under Build Events, there should be a section called Pre-Build Events. A command like del your-files would probably suffice.
The answer linked below gave some other decent options.
How to delete files in Visual Studio Pre-build event command line
The CMake command was the solution to my issues with a Qt qrc file containing QML resources.
Since it was requested in the comments, I'm publishing the solution I came up with. So, in my case the qrc file is added to the Visual Studio solution, and has a proper Custom Build Tool set (but that is the common way and should be set up by the VS Qt plugin) like this:
All I had to do was to make a trivial C# program which reads the contents of the qrc and updates the modification timestamp of the qrc file, if any of the contained items was newer than the qrc itself. This is all it takes:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
using System.Xml.Serialization;
using System.IO;
namespace QrcValidator
{
class Program
{
static void Main(string[] args)
{
if (args.Length != 1)
{
System.Console.WriteLine("usage: QrcValidator.exe <qrc file path>");
return;
}
Console.WriteLine(string.Format("Validating {0}", args[0]));
XDocument qrcDocument = XDocument.Load(args[0]);
var qrcFileLastWrtieTimeUtc = File.GetLastWriteTimeUtc(args[0]);
foreach (var file in qrcDocument.Descendants("RCC").Descendants("qresource").Descendants("file"))
{
if (File.GetLastWriteTimeUtc(file.Value) >= qrcFileLastWrtieTimeUtc)
{
Console.WriteLine("{0} is dirty, setting last write time of {1} to current UTC time", file.Value, args[0]);
File.SetLastWriteTimeUtc(args[0], DateTime.UtcNow);
Environment.Exit(0);
}
}
}
}
}
This tool takes the qrc file as the first argument. So I just added calling this tool as a pre build event, and if any changes have happened to the resources, the qrc file is touched, and it's normal build command is invoked.

Configuring cpp sources in gradle

I have set up a project on top of Qt (so source is written in C++) and I wanted to try Gradle for automatic builds on that. It took me some time to get into the details of configuring a multi project build (there is an executable and two libs) and now I am trying to tell the cpp-exe and the cpp-lib plugin how my source tree is structured.
I have set up a task that should print all of the source sets (there should be at least the default ones right?) and it looks like this:
task projectinfo {
description = "Informations about the current project"
group = INFORMATIONS_GROUP
doFirst {
task -> print ("""${task.project.sourceSets.all}""")
}
If I run this task Gradle tells me that there is no property "sourceSets" for the project. The documentation of the plugin tells me that it is possible to customize the source locations, but not how.
So my question would be: How can I tell the Gradle cpp plugin which source files to use. If there is any documentation about the cpp plugin apart from its API documentation and the Gradle user guide that would be helping too.
Have a look at Adam Murdoch's usage of Gradle's 'cpp plugin'. I believe he's one of the main Gradle submitters, so he should know how to use this better than anyone:
Exert from native-platform/build.gradle
cpp {
sourceSets {
main {
source.exclude 'curses.cpp'
}
curses {
source.srcDirs = ['src/main/cpp']
source.include 'curses.cpp'
source.include 'generic.cpp'
source.include 'generic_posix.cpp'
}
}
}
Then, within the 'libraries' node, refer to all/any combination of architecture and source sets:
sourceSets << cpp.sourceSets.main
sourceSets << cpp.sourceSets.curses
I've not had too long to look over it myself, but it looks like he defines a number of OS architecture based source code include combinations and stores these in the variants variable. He then processes them into platform JARs (I haven't actually ran the build yet, maybe I should).
Also, take a look at https://github.com/rklaren/GradleJNI, it uses the cpp plugin but looks to be a little Windows-oriented.
Update - I also found https://github.com/alkemist/gradle-cpp-demo, which has an example of the 'cpp-exe' plugin building an executable.