I want to write a unix/linux program, that will use a configuration file.
My problem is, where should I put the location of the file?
I could "hardcode" the location (like /etc) into the program itself.
However, I would like it, if the user without privileges could install it (through make) somewhere else, like ~.
Should the makefile edit the source code? Or is it usually done in a different way?
Create some defaults:
/etc/appname
~/.appname
Then if you want to allow these to be overridden have your application inspect an environment variable. e.g.
$app_userconfig
$app_config
Which would contain an override path/filename.
Lastly add a command line option that allows a config to be specified at runtime, e.g.
-c | --config {filename}
It is common to use a series of places to get the location:
Supplied by the user as a command line argument (i.e. ./program -C path/to/config/file.cfg).
From an environment variable (char *path_to_config = getenv("PROGRAMCONFIG");).
Possibly look for a user specific or local version (stat("./program.cfg") or build up a strig to specify either "$HOME/.program/config.cfg" or "$HOME/.program.cfg" and stat that).
Hardcoded as a backup (stat("/etc/program/config.cfg",...)).
keeping a global config file under /etc/prgname is a standard. Also allowing a .local config file for individual users that will override the global settings would allow each user to personalize the program to their preference.
As skaffman says, the canonical locations for things like config files are specified in FHS. There appears to be a convention that a program will read a config file from the directory from which it is run as an alternative to the one in the hard-coded location. You may wish to consider adding a command-line switch that allows a user to specify an alternative config file location, as well.
The makefile shouldn't modify the source directly, but it can pass a folder path/name to the compiler through the -D option. One way to handle it would be to #define something like DEFAULT_PATH to be the default installation path. If the user wants to define a path, the makefile would add -DUSER_PATH=whatever to the compiler options. You would write your code to use USER_PATH if it exists, and DEFAULT_PATH otherwise.
Related
Where is the following syntax used in a feature configuration (.prf) file? defined:
$$[QT_HOST_DATA/get]
I know $$[ ... ] is to access QMake properties as explained in the Qt doc, but where is the /get part of the notation in $$[QT_HOST_DATA/get] clarified? And what does it precisely do?
Also, inside a Qt .conf file, what is the difference between include (for other .conf files) and load() (for .prf files)?
If include(some.conf) merely consists in the contents of some.conf to be literally pasted into the including .conf file, what does load() do exactly?
I have found no info about the structure of .prf files.
https://doc.qt.io/qt-5/qmake-advanced-usage.html says that you can create .prf files, but says nothing about how these files are processed or should be structured?
Thanks for any clarifications you can provide!
where is the /get part of the notation in $$[QT_HOST_DATA/get] clarified? And what does it precisely do?
Nowhere, except qmake source code. It looks like all qmake properties may have upto four special "subproperies": xxx/dev xxx/src xxx/raw xxx/get. However, what are they used for is a mystery. Executing qmake -query QT_HOST_DATA/get produces (on my machine) just the same value as plain $$[QT_HOST_DATA].
I have found no info about the structure of .prf files.
Basically, .prf is just "system include file". There are two points, though:
All .prf files reside in a known location(s) pointed by QMAKEFEATURES variable.
BTW. QMAKEFEATURES is a sort of "protected variable". I managed to change it only with the help of (another undocumented) cache() function:
QMAKEFEATURES *= mydir # '*=' because of 3 passes under Windows
# 'transient' prevents creation file on disk
# only 'super' seems to work OK; no idea what's wrong with 'stash' or 'cache'
cache(QMAKEFEATURES, set transient super)
# now I can load .prf from <mydir> too...
Prf can be implicitly loaded by mentioning it in CONFIG variable. For example, CONFIG += qt (which is the default, btw.) results in include of <SomePrefix>/share/qt5/mkspecs/features/qt.prf Note that this takes place after the whole .pro was processed, so .prf file can be used to post-process user options.
what does load() do exactly?
It's just the version of include() designed specially for .prf. All it does, it simply includes .prf file. But, unlike CONFIG += xxx, it does this immediately, and, unlike plain include(), you shouldn't specify path and extension.
Let's imagine we have some script 'm12' (I've just invented this name) that runs
on Linux computers. If it is situated in your $PATH, you can easily run it
from the console like this:
m12
It will work with the default parameters. But you can customize the work of
this script by running it something like:
m12 --enable_feature --select=3
It is great and it will work. But I want to create a config file ~/.m12rc so I
will not need to specify --enable_feature --select=3 every time I run it.
It can be easily done.
The difficult part is starting here.
So, I have ~/.m12rc config file, but I what to start m12 without parameters that
are stored in that config file. What is the Unix way to do this? Should I run
script like this:
m12 --ignore_config
or there is better solution?
Next. Let's imagine I have a config file ~/.m12rc and I want some parameters from that
file, but want to change them a bit. How should I run the script and how the
script should work?
And the last question. Is it a good idea for script to first look for .m12rc
in the current directory, then in ~/ and then in /etc?
I'm asking all these questions because I what to implement config files in my
small script and I want to make the correct decisions about the design.
The book 'The Art of Unix Programming' by E S Raymond discusses such issues.
You can override the config file with --config-file=/dev/null.
You would normally use the order:
System-wide configuration (/etc/m12/m12rc, or just /etc/m12).
User's personal configuration (~/.m12rc)
Local directory configuration (./.m12rc)
Command-line options
with each later-listed item overriding earlier listed items. You should be able to specify the configuration file to read on the command line; arguably, that should be given precedence over other options. Think about --no-system-config or --no-user-config or --no-local-config. Many scripts do not warrant a system config file. Most scripts I've developed would not use both local config and user config. But that's the way my mind works.
The way I package standard options is to have a script in $HOME/bin (say m12a) that does it for me:
#!/bin/sh
exec m12 --enable_feature --select=3 "$#"
If I want those options, I run m12a. If I want some other options, I run raw m12 with the requisite options. I have multiple hundreds of files in my personal bin directory (about 500 on my main machine, a Mac; some of those are executables, but many are scripts).
Let me share my experience. I normally source config file at the beginning of the script. In the config file I also handle all the parameter switches:
DEFAULT_USER=blabla
while getopts ":u" do
case $opt in
u)
export APP_USER=$OPTARG
;;
esac
done
export APP_USER=${APP_USER-$DEFAULT_USER}
Then within the script I just use variables, this let me to have number of script having same input parameters.
In your case I imaging you would move "getopts" section to script and after it source the config file (if there was no switch to skip sourcing).
You should not put yours script config file to etc, it will require root privilidge to do that, and you simple can live with config file in home.
If you would like anyway to put your script for sharing with other users, it should go to /usr/share...
Another solution use thor (ruby gem), its way simpler to handle input parameter, avoiding work to get same result in bash e.g. getopts support only single letter switches.
I've tried to change global variable DSQUERY in Solaris with this command:
setenv DSQUERY "SYBSERVER"
but it wasn't persisted. When I entered again in the machine the value was set to the older one.
How can I persist this change?
You have to put this line in your profile file. This file is read when you start a shell, and allows you to set-up some specific settings.
The filename depends on the shell you use and how you connect (with a direct connexion or with a su for example).
It seems you use csh, so you will have to change $HOME/.cshrc and.or $HOME/.login files.
Add your SetEnv command to .cshrc and .login file will do the job.
You have to do it in the user profile files, depending on the shell being used (.login, .cshrc, .bashrc, etc) so that when you log in again, it's executed automatically. There are global versions of those files under /etc for some shells, in case you want that to be applied to all users.
Rgds,
Daniel
System-level hgrc files (in /etc/mercurial and <install-root>/etc/mercurial) are obviously platform-dependent, but how I can use platform-dependent hgrc on a per user basis?
The use case is to override a system config on a specific platform. For example, we have hg on linux and solaris with different merge tools. How do I override just the solaris merge tool, when hgrc doesn't allow any control logic (like if os.uname()[0] == 'SunOS')?
Keep a set of .<platform>.hgrc files with whatever you want to override in each one.
Set an environment variable in your .bashrc:
export PLATFORM=`python -c 'import os; print os.uname()[0],'`
In your ~/.hgrc file, use %include at the end to include the right file:
%include ~/$PLATFORM.hgrc
I'm modifying an automated build, and want to tell rpmbuild to use a specific build area when invoking it.
This is similar to an existing question, but more specific.
I don't want to run any of the build commands as the root user; the aim is only to have an RPM, not to install anything into the system.
I don't want to require the user to change their dotfiles (e.g. $HOME/.rpmrc); the build should be self-contained and not affect the user's existing settings.
I don't want to hard-code the location into the foo.spec file; that file should be useable as-is if the user wants to build in a different location.
The --buildroot option is not what I need; that sets a pseudo-root filesystem for the make part of the build process, but I need to specify the “build area” for the entire RPM build process.
What I'm looking for is a hypothetical --build-area FOODIR option that can be given to the rpmbuild command, or an equivalent environment variable. It should thus affect just that single invocation of the command and cause it to use a specified user-writable location for its build area.
I've seen references to a _topdir macro that seems to be what I'm talking about, but it doesn't appear to be configurable per invocation.
It would be ideal if rpmbuild could set up its own environment in that location when it needs it, but I don't mind setting up the directories for that per build, since that can be automated as part of the build. The goal is to have that user-writable location exist only for the duration of the build run, and then clean up by deleting that entire location once the RPM file is generated.
It's not documented, but the _topdir macro determines the build area.
So you can set this per-invocation with rpmbuild --define "_topdir ${PWD}/foobar" ... to set the directory to whatever you want.
--define is the key to setting values for any macro, not just _topdir.
The --buildroot option is not what you are looking for. The name is a bit misleading as it is not changing the buildroot but instead is setting the root for the install phase of the build. RPM is basically doing a "make install" as part of the build and is then packing the results of this. The buildroot option allows you to do this install into for example /tmp/myinstallroot.
I recently had to integrate rpm package building into an automated build and had the same problem. What i did was to generate a custom .rpmmacros file with %topdir set appropriately. I then just temporarily changes HOME to the location of that custom .rpmmacros file.
"HOME=mytopdir rpmbuild ...".