I have a C++ project using autotools to build, and Catch2 for unit testing. The details of Catch2 are probably not relevant: it's just another program I have to build and run.
I have Makefile.am set up like this (simplified):
AUTOMAKE_OPTIONS = subdir-objects
check_PROGRAMS = catch2
bin_PROGRAMS = lpsdr
common_sources = applicationcontroller.cc flowgraph.cc [...]
lpsdr_SOURCES = $(common_sources) main.cc
catch2_SOURCES = $(common_sources) test.cc
This works mostly, except it compiles everything twice, creating lpsdr-applicationcontroller.o and catch2-applicationcontroller.o, and so on for each thing in common_sources.
Of course this doubles the build time. I'd prefer to link both catch2 and lpsdr with the same object files: it will be faster to build and also ensure I'm testing exactly the same compiled code as I'm running.
Is there any way around this behavior?
I don't know if there's a way to avoid building distinct object files for each program, but the same effect can be had by building an intermediate static library, and then linking lpsdr and catch2 against that.
Something like this:
AUTOMAKE_OPTIONS = subdir-objects
noinst_LIBRARIES = liblpsdr.a
check_PROGRAMS = catch2
bin_PROGRAMS = lpsdr
liblpsdr_a_SOURCES = applicationcontroller.cc dispatcher_sink.cc [...]
lpsdr_SOURCES = main.cc
lpsdr_LDADD = liblpsdr.a
catch2_SOURCES = test.cc
catch2_LDADD = liblpsdr.a
Related
I'm using bazel to build a shared libary, but the output so file size is much bigger than expected; For comparision I also build a binary with same deps and srcs in BUILD file, the binary ouput size is much smaller; Code sample:
cc_binary(
name = "server",
srcs = ["server.cc"],
deps = [...]
) # the binary
cc_binary(
name = "libs.so",
srcs = ["server.cc"],
deps = [...],
linkshared = 1
) # the shared library
libs.so is about 5 times larger than server; It seems linkshared option packs all symbols in deps to the shared library, including unused functions, variables(nm shows libs.so contains much more symbols than server); How can I just link needed symbols to my shared library?
Well, if you're compiling a shared library, there is no such thing as "unused functions". You're creating a library with functions that an executable can use.
I'm working on a GTK3 application, but using QTCreator as my IDE, just because I happen to like it. It works fine, I can easily turn off all the QT-specific stuff and link the GTK libraries. There's just one little issue.
GTK uses XML files to define its resources. It comes with a program, "glib-compile-resources", which takes a .gresource.xml file and produces a .c file*, which can then be included in your project. The problem is that QTCreator doesn't know about glib-compile-resources, so I have to remember to run the program manually every time I make any change to them.
I've tried using a custom build step, but if I do that, then QT rebuilds the file every time, even if it hasn't changed, which slows the process down. In addition, if the C file doesn't already exist, it will fail with a "No rule to make target 'x.c' needed by 'x.o'. Stop." error, so I have to run the program manually anyway.
Is there any way to tell QTCreator to run glib-compile-resources whenever it encounters a .gresource.xml file, and include the resulting C file into the final compilation?
*There are other options available then just a straight C source file, but C source is the simplest and easiest for me.
You can add a custom target in your qmake file (rather than in your QtCreator project config). See the qmake docs at https://doc.qt.io/qt-5/qmake-advanced-usage.html#adding-custom-targets and/or https://doc.qt.io/qt-5/qmake-advanced-usage.html#adding-compilers.
Update: this is a simple example which shows how to do this for a single file, using the custom target mechanism in your .pro file:
glib_resources.target = glib-resources.c
glib_resources.depends = glib-resources.xml
glib_resources.commands = glib-compile-resources --target $$glib_resources.target --generate-source $$glib_resources.depends
QMAKE_EXTRA_TARGETS += glib_resources
PRE_TARGETDEPS += glib-resources.c ## set this target as a dependency for the actual build
QMAKE_CLEAN += glib-resources.c ## delete the file at make clean
Here's how I wound up solving my own issue:
I found in the QT documentation how to add your own custom compiler to a QT project file. The exact lines needed are:
GLIB_RESOURCE_FILES += \
resources.gresource.xml
# Add more resource files here.
glib_resources.name = glibresources
glib_resources.input = GLIB_RESOURCE_FILES
glib_resources.output = ${QMAKE_FILE_IN_BASE}.c
glib_resources.depend_command = glib-compile-resources --generate-dependencies ${QMAKE_FILE_IN}
glib_resources.commands = glib-compile-resources --target ${QMAKE_FILE_OUT} --sourcedir ${QMAKE_FILE_IN_PATH} --generate-source ${QMAKE_FILE_IN}
glib_resources.variable_out = SOURCES
glib_resources.clean = ${QMAKE_FILE_OUT}
QMAKE_EXTRA_COMPILERS += glib_resources
(Thanks to #zgyarmati, who's post lead me to the right answer.)
I'm currently working with a third party library, which has headers declared using angular brackets, like a standard library :
#include <header.h>
However, these headers are installed in a non standard place, something like /opt/company/software/version/part_software/include
With a more traditional builder like MAKE, I can just use CXXFLAGS to indicate to g++ to look in this folder too for libraries, which finally comes down to pass a -I/opt/company/software/version/part_software/include option to g++.
When trying to do the same thing in bazel, using copts = [ "-I/opt/company/software/version/part_software/include" ], I get a "path outside of the execution root" error.
It's my understanding that bazel don't like the place where the lib is installed because the build needs to be reproducible, and including a library located outside the execution root violate this constraint.
A ugly hack I've come with is to create symbolic link of the headers in /usr/local/include, and use copts = [ "-I/usr/local/include" ] in the bazel build. However, I find this approach very hacky, and I'd like to find a more bazely approach to the problem.
Note : I can't install the program during the bazel build, as it uses a closed installer on which I have no control over. This installer can't be run in the bazel's sandboxed environment, as it needs to write on certain paths not accessible within the environment.
So, it turns out that the bazelesque way of including a third part library is simply to create package encapsulating the library.
Thanks to this useful discussion, I've managed to create a package with my third party library.
First we need a BUILD file, here named package_name.BUILD
package(
default_visibility = ["//visibility:public"]
)
cc_library(
name = "third_party_lib_name", #name to reference the third party library in other BUILD files
srcs = [
"external/soft/lib/some_lib.so", #.so files to include in the lib
"software/lib/os/arch/lib_some_plugin.so",
],
hdrs = glob([ # the glob takes all the headers needed
"software/include/**/*.h",
"software/include/**/*.hpp",
]),
includes = ["software/include/"], # Specify which files are included when we use the library
)
Now we need to reference the lib a a submodule in the WORKSPACE file :
new_local_repository(
name = "package_name",
path = "opt/company/software/version",
# build_file: path to the BUILD file, here in the same directory that the main WORKSPACE one
build_file = __workspace_dir__ + "/package_name.BUILD",
)
Now, instead of using copt to references the needed headers, I'm just adding a line to the deps of the cc_rule when needed, e.g :
cc_library(
name="some_internal_lib",
srcs = ["some_internal_lib.cc"],
deps = [
"#package_name//:third_party_lib_name", #referencing the third party lib
],
)
I'm currently working on a c++ project that uses bjam (boost build) as a builder. For now I was quite happy with this build system and everything works nicely, however with one exception which I could not find an easy solution for:
I would like to have a build configuration of this project, in which the user is able to switch on or off certain modules and its dependencies (also automatic checks if software is not found -> disable module..). With dependencies I mean for example applications that require this module to work. So these applications should also not be built when the module is disabled.
Since I found nothing out there that could do this job for me, I created some variables in the jamroot (top level jamfile) that resemble the module structure of the project, and I use these variables in if statements within the appropriate jamfiles to switch on and off things. See below for an example:
Jamroot excerpt:
constant build_DataReader : 1 ;
constant build_RootReader : 1 ;
constant build_AsciiReader : 1 ;
if $(build_DataReader) {
build-project DataReader ;
}
Jamfile for DataReader Module:
sources = [ glob *.cpp ] ;
if $(build_RootReader)
{
build-project RootReader ;
sources = $(sources) $(DATAREADER)/RootReader//RootReader ;
}
if $(build_AsciiReader)
{
build-project AsciiReader ;
sources = $(sources) $(DATAREADER)/AsciiReader//AsciiReader ;
}
# Build libDataReader.so
lib DataReader :
$(sources)
;
install dist : DataReader : <location>$(TOP)/lib ;
However this is not a very elegant solution, as I would constantly have to update these hardcoded if statements when dependencies change etc.. In addition it is annoying to have to construct this tree structure of the modules in the project myself, as boost build is constructing the same thing internally by itself. Is there some kind of option in boost build to make the building of applications optional in case some requirements are not built in the current build process?
The only solution I see at the moment would be to construct a complete new config tool that would create the jamfiles for me like I want them (preprocessor). However this is work I do not want to start, and I don't really believe that there is nothing out there that is able to do what seems to me like pretty common stuff. But probably I missed something completely...
Hope I explained it in an understandable way, thanks in advance!
Steve
I'm trying to use clang to profile a project I'm working on. The project includes a rather large static library that is included in Xcode as a dependency.
I would really like clang to not analyze the dependencies' files, as it seems to make clang fail. Is this possible? I've been reading the clang documentation, and I haven't found it.
As a last resort, there is a brute force option.
Add this to the beginning of a file:
// Omit from static analysis.
#ifndef __clang_analyzer__
Add this to the end:
#endif // not __clang_analyzer__
and clang --analyze won't see the contents of the file.
reference: Controlling Static Analyzer Diagnostics
So, this isn't really an answer, but it worked well enough.
What I ended up doing was building the static library ahead of time, and then building the project using scan-build. Since there was already an up-to-date build of the static library, it wasn't rebuilt and thus wasn't scanned.
I'd still love to have a real answer for this, though.
Finally, in 2018 the option was implemented.
Use --exclude <path> [1] [2] option
--exclude
Do not run static analyzer against files found in this directory
(You can specify this option multiple times). Could be useful when
project contains 3rd party libraries.
I don't use XCode, but using scan-build in linux the following works for me. I my case, I want to run the static analysis on all first party, non-generated code. However, I want to avoid running it on third_party code and generated code.
On the command line, clang-analyzer is hooked into the build when scan-build sets CC and CXX environment variables to ccc-analyzer and c++-analyzer locations. I wrote two simple scripts called ccc-analyzer.py and c++-analyzer.py and hooked them in to the compile in place of the default. In these wrapper scripts, I simply looked at the path of the file being compiled and then run either the raw compiler directly (if I wish to avoid static analysis) or the c*-analyzer (if I wish for static analysis to occur). My script is in python and tied to my specific build system, but as an example that needs modification:
import subprocess
import sys
def main(argv):
is_third_party_code = False
for i in range(len(argv)):
arg = argv[i]
if arg == '-c':
file_to_compile = argv[i + 1]
if '/third_party/' in file_to_compile or \
file_to_compile.startswith('gen/'):
is_third_party_code = True
break
if is_third_party_code:
argv[0] = '/samegoal/bin/clang++'
else:
argv[0] = '/samegoal/scan-build/c++-analyzer'
return subprocess.call(argv)
if __name__ == '__main__':
sys.exit(main(sys.argv))
For Xcode users, you can exclude individual files from static analyzer by adding the following flags in the Target -> Build Phases -> Compile Sources section: -Xanalyzer -analyzer-disable-all-checks