Intltool with an autoconf-generated .desktop file - internationalization

In the Emperor project, I'm having some issues getting intltool to work when doing an out-of-tree build. When running make check out-of-tree, which is one of the things make distcheck does, intltool fails thus:
INTLTOOL_EXTRACT="/usr/bin/intltool-extract" XGETTEXT="/usr/bin/xgettext" srcdir=../../po /usr/bin/intltool-update --gettext-package emperor --pot
can't open ../../po/../data/emperor.desktop.in: No such file or directory at /usr/bin/intltool-extract line 212.
intltool is looking for emperor.desktop.in, which is listed in po/POTFILES.in, in the source tree. However, emperor.desktop.in is generated by the configure script from a file called emperor.desktop.in.in, in order to insert the installed executable path as configured by the user, and lands in the build tree.
These are the relevant bootstrap.sh lines:
echo +++ Running intltoolize ... &&
intltoolize --force --copy &&
cat >>po/Makefile.in.in <<EOF
../data/_column_names.h:
cd ../data && \$(MAKE) _column_names.h
EOF
The setup code in configure.ac:
IT_PROG_INTLTOOL([0.35.0])
GETTEXT_PACKAGE=emperor
AC_SUBST(GETTEXT_PACKAGE)
AC_DEFINE_UNQUOTED([GETTEXT_PACKAGE], ["$GETTEXT_PACKAGE"],
[The domain to use with gettext])
AM_GLIB_GNU_GETTEXT
data/emperor.desktop.in is listed in AC_CONFIG_FILES.
data/Makefile.am contains these lines:
desktopdir = $(datadir)/applications
desktop_in_files = emperor.desktop.in
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
#INTLTOOL_DESKTOP_RULE#
and po/POTFILES.in contains the line
data/emperor.desktop.in
You can review all the details in the public git repository if you wish.
Can I somehow tell intltool that this file will be located in the build tree, not in the source tree? Otherwise, my options appear to be to break make distcheck (not a great option), or to ship a desktop file that doesn't include the full path and assumes that the executable is installed in the PATH. (just as messy, IMHO) - Any other options?

In your source code you have emperor.desktop.in.in, which does not seem to be in any rule as a dependency. That file has to be converted first to emperor.desktop.in and later to emperor.desktop, which does not seem to be the case in your data/Makefile.am.
desktopdir = $(datadir)/applications
desktop_in_in_files = emperor.desktop.in.in
desktop_in_files = $(desktop_in_in_files:.desktop.in.in=.desktop.in)
desktop_DATA = $(desktop_in_files:.desktop.in=.desktop)
#INTLTOOL_DESKTOP_RULE#
[...]
EXTRA_DIST = \
$(desktop_in_in_files) \
[...]
$(desktop_in_in_files) contains $(desktop_in_in_files), and Makefile will know how to deal with that.

Some further digging has brought me believe that the answer is: intltool does not support source files that aren't source files in the project. Ergo, any additional processing must be done after intltool is through
Intltool requires the lines in POTFILES to be relative to the (build-time) working directory. The file POTFILES is generated by the configure script from POTFILES.in with a simple sed script defined in the IT_PO_SUBDIR autoconf macro (called by IT_PROG_INTLTOOL) that simply prepends the relative location of the top-level source directory to the paths. Alas, modifying POTFILES does not help: the intltool-extract script does everything it can to get the source directory right. I don't believe files that are sometimes inside and sometimes outside the source tree can be supported without modifying intltool itself.

Related

knit Rmarkdown moderncv to pdf using makefile with sty file in subdirectory

I am using the moderncv class to create a CV in Rmarkdown. In order to make the cv reproducible out of the box I have included the .cls and .sty files in the root directory. However, in an effort to keep the root directory uncluttered I would prefer to keep all the moderncv related files in a subdirectory (assets/tex/). I am able to access the .cls file using a relative path in the yaml front matter, but I am not able to access the .sty files unless they are in the root directory.
Searching previous questions on stackoverflow I learned the following: (1) keeping .cls and .sty files in nested directories is not recommended. I understand this and would like to do it anyway so that other people can fork my project and be able to knit the cv without having to deal with finding their texmk folder. (2) the solution to my problem seems to involve setting the TEXINPUTS using a Makefile (see this thread and another thread)
I am not very good with Makefiles, but I have managed to get one working that will knit my .Rmd file to pdf without problems, so long as the .sty files are still in root. This is what it looks like currently:
PDF_FILE=my_cv.pdf
all : $(PDF_FILE)
echo All files are now up to date
clean :
rm -f $(PDF_FILE)
%.pdf : %.Rmd
Rscript -e 'rmarkdown::render("$<")'
My understanding is that I can set the TEXINPUTS using:
export TEXINPUTS=".:./assets/tex:"
Where "assets/tex" represents the subdirectory where the .sty files are located. I do not know how to incorporate the above code into my makefile so that the .sty files are recognized in the subdirectories and my .Rmd is knit to PDF. In its current state, I get the following error if I remove the .sty files from root and put then in the aforementioned subdirectory:
! LaTeX Error: Command \fax already defined.
Or name \end... illegal, see p.192 of the manual.
which I assume is occurring because the moderncv class needs---and cannot locate---the relevant .sty files.
You could try to define the environment variable in the make rule:
%.pdf : %.Rmd
export TEXINPUTS=".:./assets/tex:"
Rscript -e 'rmarkdown::render("$<")'
Or you could set the environment variable in a set-up chunk in your Rmd file:
```{r setup, include = FALSE}
Sys.setenv(TEXINPUTS=".:./assets/tex:")
```
Note: Not tested due to lack of minimal example.

autoconf: how do I substitute the library prefix?

CLISP's interface to PARI is configured with the configure.in containing AC_LIB_LINKFLAGS([pari]) from lib-link.m4.
The build process also requires the Makefile to know where the datadir of PARI is located. To this end, Makefile.in has
prefix = #LIBPARI_PREFIX#
DATADIR = #datadir#
and expects to find $(DATADIR)/pari/pari.desc (normally
/usr/share/pari/pari.desc or /usr/local/share/pari/pari.desc).
This seems to work on Mac OS X where PARI is installed by homebrew in /usr/local (and LIBPARI_PREFIX=/usr/local), but not on Ubuntu, where PARI is in /usr, and LIBPARI_PREFIX is empty.
How do I insert the location of the PARI's datadir into the Makefile?
PS. I also asked this on the autoconf mailing list.
PPS. In response to #BrunoHaible's suggestion, here is the meager attempt at debugging on Linux (where LIBPARI_PREFIX is empty).
$ bash -x configure 2>&1 | grep found_dir
+ found_dir=
+ eval ac_val=$found_dir
+ eval ac_val=$found_dir
You are trying to use $(prefix) in an unintended way. In an Autotools-based build system, the $(prefix) represents a prefix to the target installation location of the software you're building. By setting it in your Makefile.in, you are overriding the prefix that configure will try to assign. However, since you appear not to have any installation targets anyway, at least at that level, that's probably more an issue of poor form than a cause for malfunction.
How do I insert the location of the PARI's datadir into the Makefile?
I'd recommend computing or discovering the needed directory in your configure script, and exporting it to the generated Makefile via its own output variable. Let's take the second part first, since it's simple. In configure.in, having in some manner located the wanted data directory and assigned it to a variable
DATADIR=...
, you would make an output variable of that via the AC_SUBST macro:
AC_SUBST([DATADIR])
Since you are using only Autoconf, not Automake, you would then manually receive that into your Makefile by changing the assignment in your Makefile.in:
DATDIR = #DATADIR#
Now, as for locating the data directory in the first place, you have to know what you're trying to implement before you can implement it. From your question and followup comments, it seems to me that you want this:
Use a data directory explicitly specified by the user if there is one. Otherwise,
look for a data directory relative to the location of the shared library. If it's not found there then
(optional) look under the prefix specified to configure, or specifically in the specified datadir (both of which may come from the top-level configure). Finally, if it still has not been found then
look in some standard locations.
To create a configure option by which the user can specify a custom data directory, you would probably use the AC_ARG_WITH macro, maybe like this:
AC_ARG_WITH([pari-datadir], [AS_HELP_STRING([--with-pari-datadir],
[explicitly specifies the PARI data directory])],
[], [with_pari_datadir=''])
Thanks to #BrunoHaible, we see that although the Gnulib manual does not document it, the macro's internal documentation specifies that if AC_LIB_LINKFLAGS locates libpari then it will set LIBPARI_PREFIX to the library directory prefix. You find that that does work when the --with-libpari option is used to give it an alternative location to search, so I suggest working with that. You certainly can try to debug AC_LIB_LINKFLAGS to make it set LIBPARI_PREFIX in all cases in which the lib is found, but if you don't want to go to that effort then you can work around it (see below).
Although the default or specified installation prefix is accessible in configure as $prefix, I would suggest instead going to the specified $datadir. That is slightly tricky, however, because by default it refers to the prefix indirectly. Thus, you might do this:
eval "datadir_expanded=${datadir}"
Finally, you might hardcode a set of prefixes such as /usr and /usr/local.
Following on from all the foregoing, then, your configure.in might do something like this:
DATADIR=
for d in \
${with_pari_datadir} \
${LIBPARI_PREFIX:+${LIBPARI_PREFIX}/share/pari} \
${datadir_expanded}/pari \
/usr/local/share/pari \
/usr/share/pari
do
AS_IF([test -r "$[]d/pari.desc"], [DATADIR="$[]d"; break])
done
AS_IF([test x = "x$DATADIR"], [AC_MSG_ERROR(["Could not identify PARI data directory"])])
AC_SUBST([DATADIR])
Instead of guessing the location of datadir, why don't you ask PARI/GP where its datadir is located? Namely,
$ echo "default(datadir)" | gp -qf
"/usr/share/pari"
does the trick.

automake: how set path to linker script?

I've just set up a cross-helloworld automake project (for stm32f4-discovery). There I have a custom discovery.ld scrpt. I put a line in my Makefile.amAM_LDFLAGS = -T discovery.ld. The problem starts when I run confgure from a different folder (e.g. /path/to/source/build) to the one in which the script is situated (/path/to/source). Effectively, being in /path/to/source/build directory, make runs gcc -T discovery.ld ... and fails to find the script because it's in /path/to/source directory and it's not included in the search path list.
-L/path/to/source or -L.. would solve the problem but I don't want to hardcode things.
Maybe there a autoconf/automake variable exists which points to the folder where configure script (and also my discovery.ld) are situated so that I could use it in my Makefile.am?
I'd be glad to any advice.
Many thanks to William Pursell:
AM_LDFLAGS = -T $(top_srcdir)/path/to/discovery.ld

Add extra file into the rpm building process

i have the source-code of an application that supports adding python plugins. i have written a python script and want to build a custom rpm that by-default includes my script. So that i do not have to additionally add it after the rpm installation.
Now as far as i understand, there are two parts to this-
Adding the file to the source code.
Listing that file in the .spec file.
How do i know where to put the file in the source? How do i specify the path where i want my script to be copied? The spec file contains text like-
%if %{with_python}
%files python
%{_mandir}/man5/collectd-python*
%{_libdir}/%{name}/python.so
//Something like this?
// %{_libdir}/%{name}/gearman.py
// %{_libdir}/%{name}/redis.py
%endif
You need to know where to place your script file on the target installation (e.g. /usr/lib/myApp/plugins/myNiceScript.py)
In the spec-File (section %install) you have to copy your script under %{buildroot} into the target directory (which has to be created first.
%install
...
# in case the dir does not exist:
mkdir -p %{buildroot}/usr/lib/myApp/plugins
cp whereitis/myNiceScript.py %{buildroot}/usr/lib/myApp/plugins
At the end you have to define the file flags in the %files section. E.g. if your file has to have 644 under root:
%files
...
%defattr(644,root,root)
/usr/lib/myApp/plugins/myNiceScript.py
If your plugins directory is to be created during installation you need to define these flags too:
%defattr(755,root,root)
%dir /usr/lib/myApp/plugins

Using CMake, how can I concat files and install them

I'm new to CMake and I have a problem that I can not figure out a solution to. I'm using CMake to compile a project with a bunch of optional sub-dirs and it builds shared library files as expected. That part seems to be working fine. Each of these sub-dirs contains a sql file. I need to concat all the selected sql files to one sql header file and install the result. So one file like:
sql_header.sql
sub_dir_A.sql
sub_dir_C.sql
sub_dir_D.sql
If I did this directly in a make file I might do something like the following only smarter to deal with only the selected sub-dirs:
cat sql_header.sql > "${INSTALL_PATH}/somefile.sql"
cat sub_dir_A.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_C.sql >> "${INSTALL_PATH}/somefile.sql"
cat sub_dir_D.sql >> "${INSTALL_PATH}/somefile.sql"
I have sort of figured out pieces of this, like I can use:
LIST(APPEND PACKAGE_SQL_FILES "some_file.sql")
which I assume I can place in each of the sub-dirs CMakeLists.txt files to collect the file names. And I can create a macro like:
CAT(IN "${PACKAGE_SQL_FILES}" OUT "${INSTALL_PATH}/somefile.sql")
But I am lost between when the CMake initially runs and when it runs from the make install. Maybe there is a better way to do this. I need this to work on both Windows and Linux.
I would be happy with some hints to point me in the right direction.
You can create the concatenated file mainly using CMake's file and function commands.
First, create a cat function:
function(cat IN_FILE OUT_FILE)
file(READ ${IN_FILE} CONTENTS)
file(APPEND ${OUT_FILE} "${CONTENTS}")
endfunction()
Assuming you have the list of input files in the variable PACKAGE_SQL_FILES, you can use the function like this:
# Prepare a temporary file to "cat" to:
file(WRITE somefile.sql.in "")
# Call the "cat" function for each input file
foreach(PACKAGE_SQL_FILE ${PACKAGE_SQL_FILES})
cat(${PACKAGE_SQL_FILE} somefile.sql.in)
endforeach()
# Copy the temporary file to the final location
configure_file(somefile.sql.in somefile.sql COPYONLY)
The reason for writing to a temporary is so the real target file only gets updated if its content has changed. See this answer for why this is a good thing.
You should note that if you're including the subdirectories via the add_subdirectory command, the subdirs all have their own scope as far as CMake variables are concerned. In the subdirs, using list will only affect variables in the scope of that subdir.
If you want to create a list available in the parent scope, you'll need to use set(... PARENT_SCOPE), e.g.
set(PACKAGE_SQL_FILES
${PACKAGE_SQL_FILES}
${CMAKE_CURRENT_SOURCE_DIR}/some_file.sql
PARENT_SCOPE)
All this so far has simply created the concatenated file in the root of your build tree. To install it, you probably want to use the install(FILES ...) command:
install(FILES ${CMAKE_BINARY_DIR}/somefile.sql
DESTINATION ${INSTALL_PATH})
So, whenever CMake runs (either because you manually invoke it or because it detects changes when you do "make"), it will update the concatenated file in the build tree. Only once you run "make install" will the file finally be copied from the build root to the install location.
As of CMake 3.18, the CMake command line tool can concatenate files using cat. So, assuming a variable PACKAGE_SQL_FILES containing the list of files, you can run the cat command using execute_process:
# Concatenate the sql files into a variable 'FINAL_FILE'.
execute_process(COMMAND ${CMAKE_COMMAND} -E cat ${PACKAGE_SQL_FILES}
OUTPUT_VARIABLE FINAL_FILE
WORKING_DIRECTORY ${CMAKE_CURRENT_LIST_DIR}
)
# Write out the concatenated contents to 'final.sql.in'.
file(WRITE final.sql.in ${FINAL_FILE})
The rest of the solution is similar to Fraser's response. You can use configure_file so the resultant file is only updated when necessary.
configure_file(final.sql.in final.sql COPYONLY)
You can still use install in the same way to install the file:
install(FILES ${CMAKE_CURRENT_BINARY_DIR}/final.sql
DESTINATION ${INSTALL_PATH})

Resources