// ^^^^^^^^^^^^^^^^ this is module part, this goes somewhere into your global project files ^^^^^^^^^^^^^^^^^^^^
import qbs
import qbs.FileInfo
import qbs.File
import qbs.Utilities
Module {
// this uses an external dependency "conditionals " to inject some properties
// will vary depending on where you store it or you can drop it altogether
qbsSearchPaths: product.sourceDirectory + "/../../modules"
// protobuf is very finicky about where you invoke it from.
// can't just do it from where its executable, or .proto files are stored
// this varable needs to be passed from outside
property string rootDir: ""
// to disable some compiler warnings we need to know which is used on .cpp files
property var toolchain: []
// see rootDir comment
property string generationDir: ""
// path to where protobuf stores its custom types
property string protobufDependencyDir: ""
Rule {
// this is what makes a rule pick up your proto files in files where
// this module is referenced
inputs: ["proto"]
Artifact {
// this is the name for the resulting artifact.
filePath: FileInfo.path(input.filePath) + '/' + FileInfo.baseName(input.fileName) + '.pb.cc'
// flags: "cpp" makes them auto picked up by further modules to be automatically compiled into your project
fileTags: "cpp"
// disabling some gcc whining
cpp.cxxFlags: {
var flags = []
if(!input.moduleProperty('proto_generation', 'toolchain').contains("msvc"))
flags = [ "-Wno-unused-variable", "-Wno-unused-parameter"]
return flags
}
}
prepare: {
// we need to know where protoc is stored if it isn't in the PATH
// I prefer to manually set this path in .qbs anyway
var protoc = product.moduleProperty('conditionals', 'protoc');
// use of canonicalFilePath is discourage because it might break on symlinks
// iirc canonicalFilePath transforms ../ relative file paths into absolute which is important
// since your .proto files are liekly to use relative
// note that we can't directly reference proto_generation module properties here and have to pick them up via input.
var rootDir = File.canonicalFilePath(input.moduleProperty('proto_generation', 'rootDir'))
var generationDir = File.canonicalFilePath(input.moduleProperty('proto_generation', 'generationDir'))
var pbDependencyDir = File.canonicalFilePath(input.moduleProperty('proto_generation', 'protobufDependencyDir'))
// the rest is more or less self explanatory
if(generationDir === "")
generationDir = rootDir
var protoArgs = [];
protoArgs = protoArgs.concat(["--proto_path=" + rootDir]);
protoArgs = protoArgs.concat(["--proto_path=" + pbDependencyDir]);
protoArgs = protoArgs.concat(["--cpp_out=" + generationDir]);
protoArgs = protoArgs.concat(input.filePath);
var protoCommand = new Command(protoc, protoArgs);
protoCommand.description = 'Generating classes from: ' + input.fileName;
return [protoCommand];
}
}
}
// then in the Product
// this reference basically plugs in generation module and automatically makes qbs know what to do with .proto files
Depends { name: "proto_generation" }
// you reference the files that are used for generation, slap a tag that module knows onto them
// and when the build starts they are pick automatically and the results are _automatically_ injected
// into your sources. no further referencing of resulting .cpp files in .qbs file is needed
Group{
name:"proto files"
files: [
"../ParserLib/proto/error.proto",
]
// note that module settign are on a PER GROUP basis
// you can totally have different groups with different settings within a single product
proto_generation.rootDir:sourceDirectory + "/proto"
proto_generation.protobufDependencyDir: sourceDirectory + "/../../external"
proto_generation.toolchain: qbs.toolchain
fileTags: ["proto"]
}