Expand macro inside doxygen comment for printing out software version - c++

I have some C++ code base, documented with doxygen, and build with GNU make.
Version information is centralized in makefile, where I have something like:
VERSION=1.2.3.4
In my makefile, the CFLAGS add the following define:
CFLAGS += -DAPP_VERSION=$(VERSION)
This enables me to get the version in code, like this:
#define STR_EXPAND(tok) #tok
#define STR(tok) STR_EXPAND(tok)
int main()
{
cout << "software version is << STR(APP_VERSION) << endl;
}
Now, what I would like is to have this in the doxygen-produced html files:
Current version of software is 1.2.3.4
I managed to export the makefile variable into the doxygen configuration file with:
(edit: doxygen is called from makefile, through a 'make-doc' target)
PREDEFINED = APP_VERSION=$(VERSION)
But then, if I try in the doxygen \mainpage command something like this, it fails, because (of course), macro names don't get expanded in comments...
/**
\mainpage this is the doc
Current version is $(APP_VERSION) -- or -- ... is APP_VERSION
*/
Questions
Do you know of a way to "expand" that macro in the doxygen comments ? This could be done by some sed processing on the file holding the comment in the makefile, but maybe this can be solved directly with doxygen ?
How do other projects handle versioning (besides automatic versioning tool that VCS provide, I mean), in a way that the version id is uniquely defined in a file, so it can be fetched both by software build system and documentation build system.
Related: How to display a defined value

Macros in comments are not generally expanded (see, for example, this answer). This is not unique to doxygen and I can 't think of a way to do this using the PREDEFINED configuration option.
As you state in the question, you can use sed, see the third bullet point in this answer. For example, using the following
INPUT_FILTER = "sed -e 's/VERSION/1.0/'"
will replace all instances of VERSION with 1.0 in all your source files (you can specify which files to process with INPUT_FILTER, rather than processing all source files). You might not want VERSION to be expanded everywhere, so perhaps it is best to use something like $(VERSION) and sed this token. Also, you will need a way of getting your version number from your makefile and into your doxygen configuration file. This can be done with another sed.
To address your last bullet point, doxygen has the FILE_VERSION_FILTER configuration option for determining the version number of each file. Using this will print some version information (whatever is printed to standard out from the command specified in FILE_VERSION_FILTER) at the top of each file page. In the documentation there are examples of getting the version number using a number of different version control systems. Also, here is a page describing how to use git and doxygen to extract version information.
The only drawback with this configuration option is that I don't know how to specify where the file version information should appear in the final documentation. I presume you can use a layout file: I presume you can change the layout of pages, but I have never done this and don't know how easy it would be to use this to include version information on the mainpage.

You need to use the "export" functionality of make ie a very simple make file with
project_name=FooBar
export project_name
all:
doxygen Doxyfile
Will allow you to use the following comments in C++
/*! \mainpage Project $(project_name) Lorem ipsum dolor
I can see this becoming a PITA with a large set of exports but it's a fairly simple way to do it. Alternatively you could run doxygen from a separate BASH script with all the exports in it to avoid polluting your Makefile too much.

the commands manual suggests that $(VARIABLE) expands environment variables. So maybe you can put your version in an environment variable?

Related

Use autotools installation prefix

I am writing a C++ program using gtkmm as the window library and autotools as my build system. In my Makefile.am, I install the icon as follows:
icondir = $(datadir)/icons/hicolor/scalable/apps
icon_DATA = $(top_srcdir)/appname.svg
EDIT: changed from prefix to datadir
This results in appname.svg being copied to $(datadir)/icons/hicolor/scalable/apps when the program is installed. In my C++ code, I would like to access the icon at runtime for a window decoration:
string iconPath = DATADIR + "/icons/hicolor/scalable/apps/appname.svg";
// do stuff with the icon
I am unsure how to go about obtaining DATADIR for this purpose. I could use relative paths, but then moving the binary would break the icon, which seems evident of hackery. I figure that there should be a special way to handle icons separate from general data, since people can install 3rd party icon packs. So, I have two questions:
What is the standard way of installing and using icons with autotools/C++/gtkmm?
Edit: gtkmm has an IconTheme class that is the standard way to use icons in gtkmm. It appears that I add_resource_path() (for which I still need the installation prefix), and then I can use the library to obtain the icon by name.
What is the general method with autotools/C++ to access the autotools installation prefix?
To convey data determined by configure to your source files, the primary methods available are to write them in a header that your sources #include or to define them as macros on the compiler command line. These are handled most conveniently via the AC_DEFINE Autoconf macro. Under some circumstances, you might also consider converting source files to templates for configure to process, but except inasmuch as Autoconf itself uses an internal version of that technique to build config.h (when that is requested), I wouldn't normally recommend it.
HOWEVER, the installation prefix and other installation directories are special cases. They are not finally set until you actually run make. Even if you set them via the configure's command-line options, you can still override that by specifying different values on the make command line. Thus, it is not safe to rely on AC_DEFINE for this particular purpose, and in fact, doing so may not work at all (will not work for prefix itself).
Instead, you should specify the appropriate macro definition in a command-line option that is evaluated at make time. You can do this for all targets being built by setting the AM_CPPFLAGS variable in your Makefile.am files, as demonstrated in another answer. That particular example sets the specified symbol to be a macro that expands to a C string literal containing the prefix. Alternatively, you could consider defining the whole icon directory as a symbol. If you need it only for one target out of several then you might prefer setting the appropriate onetarget_CPPFLAGS variable.
As an aside, do note that $(prefix)/icons/hicolor/scalable/apps is a nonstandard choice for the installation directory for your icon. That will typically resolve to something like /usr/local/icons/hicolor/scalable/apps. The conventional choice would be $(datadir)/icons/hicolor/scalable/apps, which will resolve to something like /usr/local/share/icons/hicolor/scalable/apps.
In your Makefile.am, use the following
AM_CPPFLAGS = -DPREFIX='"$(prefix)"'
See Defining Directories in autoconf's manual.

Using ocamldoc with packs

I have an ocamlbuild project which includes some files in a subdirectory with an .mlpack file listing them.
e.g. I have a file support/logging.ml which defines the module Support.Logging. The _tags file says "support": for-pack(Support).
This all builds and runs fine. But how can I generate docs for this using ocamldoc?
The most recent post I found was ocamldoc generation and packed files from 2011, which suggests using ocp-pack to generate one large .ml file and pass that to ocamldoc. However, that doesn't take into account the build order, so the generated module doesn't work due to forward references.
What's the best way to handle this?
The problem is described in the following bugreport. Handling -pack inside ocamldoc requires an implementation effort that the maintainer is not motivated to perform, and so far nobody stepped up to contribute a patch for this feature.
In the meantime, you can easily copy your foo.mlpack file into a foo.odocl generating the documentation of the separate submodules. That's only an imperfect workaround as the doc will talk about X rather than Foo.X, but that's a least-effort solution.
Here's the solution I'm now using in my Makefile. It does work, and cross-references into the Support module work:
doc:
ocp-pack -o support.ml.tmp support/logging.ml support/common.ml support/utils.ml support/basedir.ml support/qdom.ml support/system.ml
echo '(** General support code; not 0install-specific *)' > support.ml
cat support.ml.tmp >> support.ml
rm support.ml.tmp
$(OCAMLBUILD) 0install.docdir/index.html
rm support.ml
It's hacky because:
You have to list the support.ml files in build order, by hand
The Makefile adds the doc comments for Support (otherwise, it takes the description of the first sub-module, which you don't want)

Using Sphinx-apidoc to generate documentation from C++ code

There have been a couple of threads on this topic in the past that claim Sphinx doesn't support this at all. I had my doubts but either it has been updated since or the documentation for it was quite well hidden, because here is a link on the website stating otherwise:
http://www.sphinx-doc.org/en/master/usage/restructuredtext/domains.html#cpp-domain
Anyway, I'm new to Sphinx but am trying to use it to (eventually) automate documentation using some text from some source C++ code. So far I haven't been able to get anywhere when using the sphinx-apidoc -o ... command. An almost blank document is created. I'm probably not using the right directives, since I don't know how - the supporting documentation hasn't been able to help me.
Can anyone provide some assistance with the basic steps needed to get it working? If it is not possible to auto-generate documentation from C++, what are the C++ domains for and how to use them?
On auto-generating C++ documentation:
After reading up on how to use sphinx at all, you should have a look into breathe:
Breathe provides a bridge between the Sphinx and Doxygen documentation
systems.
It is an easy way to include Doxygen information in a set of
documentation generated by Sphinx. The aim is to produce an autodoc
like support for people who enjoy using Sphinx but work with languages
other than Python. The system relies on the Doxygen’s xml output.
So additionally, you'll need to follow Doxygen commenting style and even setup an doxygen project. But I tried that and it works really well after the initial setup took place. Here is an excerpt of our CMakeLists.txt which might give you an idea on how sphinx and doxygen work together:
macro(add_sphinx_target TARGET_NAME BUILDER COMMENT_STR)
add_custom_target(${TARGET_NAME}
COMMAND sphinx-build -b ${BUILDER} . sphinx/build/${BUILDER}
WORKING_DIRECTORY docs
DEPENDS doxygen
COMMENT ${COMMENT_STR}
)
endmacro(add_sphinx_target)
add_custom_target(doxygen
COMMAND doxygen docs/doxygen.conf
COMMENT "Build doxygen xml files used by sphinx/breathe."
)
add_sphinx_target(docs-html
html
"Build html documentation"
)
So after initial setup, essentially it boils down to:
build doxygen documentation with doxygen path/to/config
cd into the directory where the sphinx configuration is.
build sphinx documentation with sphinx-build . path/to/output
On the c++ domain:
Sphinx is a „little bit“ more than a system to auto-generate documentation. I would suggest you have a look at the examples (and consider that the sphinx website itself is written in sphinx reST code). Especially click the Show Source link on many sphinx-generated pages.
So if you cannot generate documentation automatically for a project, you have to do it yourself. Basically sphinx is a reST to whatever (LaTeX, HTML, …) compiler. So you can write arbitrary text, but the advantage is that it has a lot of commands for documenting source code of different languages. Each language gets its own domain (prefix or namespace) to separate the namespaces of the different languages. So for example I can document a python function using:
.. py:function:: Timer.repeat([repeat=3[, number=1000000]])
Does something nasty with timers in repetition
(source)
I can do the same using the cpp domain:
.. cpp:function:: bool namespaced::theclass::method(int arg1, std::string arg2)
Describes a method with parameters and types.
(source)
So if you want to document your c++ project without doxygen+breathe but with sphinx, you'll have to write the restructured text files yourself. This also means that you split the documentation from your source code, which can be undesirable.
I hope that clears things up a bit. For further reading I strongly suggest that you have a good read on the sphinx tutorial and documentation until you understood what it actually does.

Using Eclipse CDT from command line

I need to have some of my C++ classes, functions and namespaces renamed as a part of my build script, which is runned by my CI system.
Unfortunatly a simple sad/awk/gsar/... technique is not enough, and I need smart rename refactoring, that carefully analyses my code.
Actually I found out, that CDT C/C++ rename refactoring does, what I need. But it does it from Eclipse IDE. So I need to find a way to start it from command line, and to make it a part of my CI build script.
I know that Eclipse has eclipsec executable, that allowes running some Eclipse functions from command line (see e.g. here).
But I can't find any suitable documentation for functions, CDT exports to command line. The only thing, I found is the this. But it doesn't solve my problem.
So, I need help to run CDT rename refactoring from command line (or someway like that). If it is not possible, may be someone will advice another tool, that can do rename refactoring for C++ from command line ?
Pragmatic Approach
"I need to have renamed as a part of my build script"
This sounds a bit like a design problem. However, I remember having been guilty of the same sin once writing a C++ application on AIX/Win32: most notably, I wanted to be able to link 'conflicting' versions of shared objects. I solved it using a simple preprocessor hack like this:
# makefile
#if($(ALTERNATIVE))
CPPFLAGS+=-DLIBNAMESPACE=MYLIB_ALTERNATIVE
#else
CPPFLAGS+=-DLIBNAMESPACE=MYLIB
#endif
./obj64/%.o: %cpp
xlC++ $(CPPFLAGS) $^ -o %#
Sample source/header file:
namespace MYLIB
{
class LibService :
{
};
}
As you can see, this required only a single
find -iname '*.[hc]pp' -o -iname '*.[hc]' -print0 |
xargs -0 sed -i 's/OldNamespace/MYLIB/g'
Eclipse Automation
You could have a look at eclim, which does most, if not all, of what you describe, however it targets the vim editor.
What eclim boasts, is full eclipse intergration (completion, refactoring, usage search etc.) from an external program. I'm not fully up to speed with the backend of eclim, but I do know that it works with a eclimd server process that exposes the service interface used by the vim plugin.
I suspect you should be able to reuse the code from eclimd if not just use eclim for your purposes.
We are completing a command-line rename tool for C++, that uses compiler accurate parsing and name resolution, including handling of shadowed names. Contact me (see bio) for further details or if you might be interested in a beta.

Info.plist value as C++ #define

In a C++ iOS project (or any other Mac OS), is there a simple way of making a value available both to the Info.pList settings, and to the code in the form of a preprocessor macro?
Ideally, I would like to have something like this
C++ code:
#define MY_VERSION_STRING "1.0"
Info.pList
CFBundleVersion: ${MY_VERSION_STRING}
Or alternatively, is there a way of getting values from the .pList in c++? (Without manually parsing the .pList as xml.)
Probably not the best solution, but you could use the /usr/libexec/PlistBuddy utility in a build script to generate a .h file containing a define with a value extracted from the plist.
To output a value from a plist:
/usr/libexec/PlistBuddy -c 'Print :Path:To:Key' filename.plist
I know this has already been answered, but I'll add my two cents for posterity. As Richard mentioned above, Xcode has a couple of options for preprocessing Info.plist files -- the most relevant to the current question are "Preprocess Info.plist" and "Info.plist Preprocessor Prefix File".
If your version information is defined in, say ver.h, you can include ver.h as the prefix file and refer to the version macro directly from Info.plist.
This is all readily doable without involving PlistBuddy at all, entirely using build settings.
you create a user defined build setting for your project/target either in the Xcode UI or if you're familiar with xcconfig files you can define it there in a completely textual = form.
you create your setting MY_VERSION_STRING with a value of 1.0 as your build setting either in Xcode or in an xcconfig file.
in your Info.plist your CFBundleVersion line would have a value of ${MY_VERSION_STRING}
you turn on Info.plist preprocessing
lastly, make use of GCC_PREPROCESSOR_DEFINITIONS build variable. for that build setting you can specify a value of MY_VERSION_STRING=${MY_VERSION_STRING} which will result in your defined and shared build setting definition available in to your c/c++/obj-c code as if you had created it as a #define
Property list can also store arrays or some binary data. How do you represent that? It is very domain-specific. So if you know exactly how do you want each type to be represented in C++, you have to either parse plist file and generate C++ code, be that preprocessor directives, or some code defining arrays, enums etc. There are PlistBuddy and plutil tools available, but they probably won't be much of a help. The easiest way for me would be to use perl, see Using Perl to Manage Plist Files for details.
Good luck!
In case anyone wants to do the same thing, this is the script I added to the target before the compilation phase:
VERSION=`/usr/libexec/PlistBuddy -c 'Print :CFBundleVersion' Info.plist`
echo "#define VERSION_STRING L\"$VERSION\"" > Version.h
If you use #define..., you shoud use in the .plist key, MY_VERSION_STRING, and not ${MY_VERSION_STRING}. This works too with the "Info.plist Preprocessor Prefix File". In both cases don't forget to set "Preprocess Info.plist File".