Is there a cmake function to update .pot files? - cmake

I am migrating a project from autotools to cmake. I have a question about gettext support.
There is an existing FindGettext.cmake modules that provides a nice function :
GETTEXT_CREATE_TRANSLATIONS(foo.pot ALL fr.po de.po)
where you provide a pot file and translated po fil ; the function takes care of turning the po files into gmo files, and add the proper installation targets to make sure the files can be found at runtime. All good and well.
Now comes the question : how do you update your pot files and you po files when you add new messages ?
For this, autotools would generate a "update-po" target, that (from what I understand), reads a POTFILES.in with the lists of all files containing translated strings, mixes it with other info, and ends up calling xgetext to generate the po. I think the coresponding Makefile task is the one that contains something like :
case `$(XGETTEXT) --version | sed 1q | sed -e 's,^[^0-9]*,,'` in \
'' | 0.[0-9] | 0.[0-9].* | 0.1[0-5] | 0.1[0-5].* | 0.16 | 0.16.[0-1]*) \
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \
--files-from=$(srcdir)/POTFILES.in \
--copyright-holder='$(COPYRIGHT_HOLDER)' \
--msgid-bugs-address="$$msgid_bugs_address" \
;; \
*) \
$(XGETTEXT) --default-domain=$(DOMAIN) --directory=$(top_srcdir) \
--add-comments=TRANSLATORS: $(XGETTEXT_OPTIONS) \
--files-from=$(srcdir)/POTFILES.in \
--copyright-holder='$(COPYRIGHT_HOLDER)' \
--package-name="$${package_gnu}ube" \
--package-version='0.4.0-dev' \
--msgid-bugs-address="$$msgid_bugs_address" \
;; \
esac
So, before I reinvent the wheel, is there an existing cmake function to do the same thing ?
Or do I have to find the xgettext executable, lists the files, and do this by hand ? THe makefile version seems quite complicated (although it seems to handle lots of cases) ; I would not mind not having to write the cmake equivalent ;)
Thanks
PH

Don't let the autotool bloat scare you. :-)
You can use the following code:
SET(_potFile ${PROJECT_NAME}.pot)
ADD_CUSTOM_COMMAND(OUTPUT ${_potFile}
COMMAND ${XGETTEXT_CMD} ${_xgettext_option_list} -o ${_potFile} ${_src_list}
DEPENDS ${_src_list}
WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}
COMMENT "Extract translatable messages to ${_potFile}"
)
ADD_CUSTOM_TARGET(pot_file ${_all}
DEPENDS ${_potFile}
)
For C programs, I am using following as _xgettext_option_list
--language=C --keyword=_ --keyword=N_ --keyword=C_:1c,2 --keyword=NC_:1c,2 -s
--package-name=${PROJECT_NAME} --package-version=${PRJ_VER}
I did reinvented the wheel when the FindGettext did not have the option ALL (when it was cmake-2.4) :-)

According to this kde wiki page, using cmake for editing sources is not a good idea. Better use standalone script for updating translations.
In fact, the extraction and merging of messages does not map well onto the CMake concept of out-of-source builds, and CMake can't
provide too much help for this step, either.
Hence, in this tutorial, we will handle the first step with a
standalone shell script, and only the second step will be handled by
CMake.

Related

can gcc make test if a defined symbol exists in a source file

Is it possible for gcc make to test if a define exists in one of the source files ie.
ifeq (DEFINED_BLAH_BLAH,3)
#echo is equal to 3
else
#echo is not equal to 3
endif
I've looked at this and to expend on the suggestion from the comment, you could do the following. Not elegant, probably not the best available solution, but it works:
echo -ne "#if 1==MYVAL\n0\n#else\n1\n#endif\n" | cpp -P -imacros test.h
Or to call it through gcc or g++:
echo -ne "#if 1==MYVAL\n0\n#else\n1\n#endif\n" | \
gcc -Xpreprocessor -P -E -imacros test.h -
These would return shell style 0 (true for MYVAL defined in test.h and being 1) or 1 on stdout which you could test for in make / shell.
You may also want to strip all blank lines appending | grep -v '^$'.
To elaborate a bit more on the above. I create (echo) as simple file that I run through the preprocessor which check for equality on given macro and results in 0 or 1 being in the output. -P for cpp, because it's not really a C file and we do not need any of the extra bits in the output. -imacros means retain the macros defined in that file, but discard any output generated by processing it.
It should also be noted, if you'd have any conditional definitions needed to consider any defines passed to the compiler, you would need to pass them to this cpp run as well.
Also note whether you test.h being your header file you know should include the macro defintion. Or main.c being a source file including that (and other) headers doesn't really matter / yields the same result (whatver the value was when cpp was done with the file read and (pre)processed for -imacros.

make targets depend on variables

I want (GNU) make to rebuild when variables change. How can I achieve this?
For example,
$ make project
[...]
$ make project
make: `project' is up to date.
...like it should, but then I'd prefer
$ make project IMPORTANTVARIABLE=foobar
make: `project' is up to date.
to rebuild some or all of project.
Make wasn't designed to refer to variable content but Reinier's approach shows us the workaround. Unfortunately, using variable value as a file name is both insecure and error-prone. Hopefully, Unix tools can help us to properly encode the value. So
IMPORTANTVARIABLE = a trouble
# GUARD is a function which calculates md5 sum for its
# argument variable name. Note, that both cut and md5sum are
# members of coreutils package so they should be available on
# nearly all systems.
GUARD = $(1)_GUARD_$(shell echo $($(1)) | md5sum | cut -d ' ' -f 1)
foo: bar $(call GUARD,IMPORTANTVARIABLE)
#echo "Rebuilding foo with $(IMPORTANTVARIABLE)"
#touch $#
$(call GUARD,IMPORTANTVARIABLE):
rm -rf IMPORTANTVARIABLE*
touch $#
Here you virtually depend your target on a special file named $(NAME)_GUARD_$(VALUEMD5) which is safe to refer to and has (almost) 1-to-1 correspondence with variable's value. Note that call and shell are GNU Make extensions.
You could use empty files to record the last value of your variable by using something like this:
someTarget: IMPORTANTVARIABLE.$(IMPORTANTVARIABLE)
#echo Remaking $# because IMPORTANTVARIABLE has changed
touch $#
IMPORTANTVARIABLE.$(IMPORTANTVARIABLE):
#rm -f IMPORTANTVARIABLE.*
touch $#
After your make run, there will be an empty file in your directory whose name starts with IMPORTANTVARIABLE. and has the value of your variable appended. This basically contains the information about what the last value of the variable IMPORTANTVARIABLE was.
You can add more variables with this approach and make it more sophisticated using pattern rules -- but this example gives you the gist of it.
You probably want to use ifdef or ifeq depending on what the final goal is. See the manual here for examples.
I might be late with an answer, but here is another way of doing such a dependency with Make conditional syntax (works on GNU Make 4.1, GNU bash, Bash on Ubuntu on Windows version 4.3.48(1)-release (x86_64-pc-linux-gnu)):
1 ifneq ($(shell cat config.sig 2>/dev/null),prefix $(CONFIG))
2 .PHONY: config.sig
3 config.sig:
4 #(echo 'prefix $(CONFIG)' >config.sig &)
5 endif
In the above sample we track the $(CONFIG) variable, writing it's value down to a signature file, by means of the self-titled target which is generated under condition when the signature file's record value is different with that of $(CONFIG) variable. Please, note the prefix on lines 1 and 4: it is needed to distinct the case, when signature file doesn't exist yet.
Of course, consumer targets specify config.sig as a prerequisite.

Gnu Makefile, compile should fail

I have a collection of examples that I want to make sure they fail to compile. What is the best way to to that with a *GNU Makefile?
test_nocompile: $(NOCOMPILE_CPP)
for cpp in $(NOCOMPILE_CPP) ; do \
echo === $$cpp === ; \
if $(CXX) $(CXXFLAGS) -c -o fail.o $$cpp ; then echo ok ; else exit 1; fi ; \
done
As you can see, I have several difficulties here:
Accessing the shell-for variable cpp: $cpp, \$cpp and $$cpp both do not work.
Even with my if the make stops after the first g++-compile fails. But thats exactly what I want. I want failing to g++-compile to be considered the correct behaviour.
Shell-for-loops in Makefiles are not the best idea. Is there a better way? I can not think of one, because since I expect the compiles to fail, I do not have a correct target, right?
Advanced and optional:
If I could manage to have the fail-check above working, I could try a second pass of compilation, this time with an additional -DEXCLUDE_FAIL, which takes out the offending line from my examples, and then the code should compile. Any idea?
or should write a Python script for that...? ;-)
Edit:
I think my "advanced and optional" gave me a very good idea right now. I could use makes dependency checking again. Just a rough sketch here:
NOCOMPILE_CPP := $(wildcard nocompile/ *.cpp)
NOCOMPILE_XFAILS := $(addsuffix .xfail,$(basename $(NOCOMPILE_CPP)))
%.xfail: %.cpp
if $(CXX) $(CXXFLAGS) -o $# $< ; then exit 1 ; else echo OK ; fi
$(CXX) $(CXXFLAGS) -DEXCLUDE_FAILCODE -o $# $<
test_nocompile: $(NOCOMPILE_XFAILS)
Is this elegant? Then I only have to work out how -DEXCLUDE_FAILCODE can make the failing tests work.... Non-trivial, but doable. I think that could do it, right?
Works for me. What do you get in echo?
You need to negate the condition in if then. Right now it quits when the file doesn't compile and AFAIU you need the opposite.
Why it's not a good idea? But you can write a script that will call $(CXX) and return a proper error code (0 if it doesn't compile). Then you may have normal targets with this script. I'm not very good with specifics of GNU make, probably it's possible with the builtin stuff.
Advanced & optional:
1. Let's first make the thing work:)
2. Personally i don't use python, therefore don't see a need here =:P

Automake pattern expansion

I'd like to include many files in one Makefile.am file in the xxx_SOURCES = ... part. Is there any way to use a typical shell expansions there? What I'm looking for is a working equivalent for:
xxx_SOURCES = xxx.c $(top_builddir)/src/{aaa,bbb,ccc}.c
1) There is no way to do that in portable Make syntax (ephemient's answer will work only with GNU Make)
2) There is no way to do that using Automake either. (Although the feature should not be too hard to implement by someone who need it...)
Personally I don't really see the advantage to using
foo_SOURCES = subdir/{foo,bar,baz}.c
over
foo_SOURCES = \
subdir/foo.c \
subdir/bar.c \
subdir/baz.c
I find the former is more cryptic, and it is not grepable (e.g. to answer the question "which Makefile mentions foo.c?").
I don't know if it's the best way, but this is what I've always done:
xxx_SOURCES = xxx.c $(shell echo $(top_builddir)/src/{aaa,bbb,ccc}.c)

How to get fully expanded variables out of configure?

I created a configure.ac file like this:
AC_INIT()
set
the purpose of this is to print every available environment variable the configure script creates using set, so I do this:
user#host:~$ autoconf
user#host:~$ ./configure
which prints a bunch of variables like
build=
cache_file=/dev/null
IFS='
'
LANG=C
LANGUAGE=C
datarootdir='${prefix}/share'
mandir='${datarootdir}/man'
no_create=
So far so good.
The problem is:
I want to expand the variables like ${prefix}/share - but piping
everything to a file example.sh and executing it using bash doesn't work, because bash complains about modifying read-only variables like UID and expansion itself doesn't seem to work either.
I tried using a makefile for this where expansion works, but it complains about newlines in strings, like in the above output the line IFS=' causes an error message Makefile:24: *** missing separator. Stop.
Does anyone have an idea how to get a fully expanded version of configure's output?
The Autoconf manual (I cannot recall or find exactly where) recommends to "manually" do such a kind of variable substitution from within a Makefile.in (or .am if you happen to use Automake):
Makefile.in
[...]
foo.sh: foo.sh.in
$(SED) \
-e 's|[#]prefix#|$(prefix)|g' \
-e 's|[#]exec_prefix#|$(exec_prefix)|g' \
-e 's|[#]bindir#|$(bindir)|g' \
-e 's|[#]datarootdir#|$(datarootdir)|g' \
< "$<" > "$#"
[...]
foo.sh.in
#!/bin/sh
datarootdir=#datarootdir#
du "$datarootdir"