libqi
1.14.5
|
go to the qi::path API reference.
The main idea of the qibuild-based project is that you always end up with the same layout.
For instance, right after having built you project, you end up with a directory looking like this:
Here we assume you have a foo
executable which:
bar
dynamic libraryfoo.data
foo.cfg
src |__ foo |__ data |___ foo.data |__ etc |__ foo.cfg build |___ sdk |__ lib |___ libbar.so |__ bin |__ foo
When everything is installed, you have something like:
prefix |__ lib |__ libbar.so |__ bin |__ foo |__ share |__ foo |__ foo.data |__ etc |__ foo |__ foo.cfg
Here is a list of common requirements:
foo/foo.cfg
, foo/foo.data
in a clean, simple way, while making sure the solution works whereas the project is built or installedfoo
may need to write or update its configuration files or data but we need to make sure nothing will be written inside the installed directoryfoo.cfg
files, we need to be able to process then in a correct order.Here is how it works:
/path/to/build/sdk
, when something is installed, the prefix is the DESTDIR
plus the installation prefix.foo.cfg
is placed in build/sdk/foo/foo.cfg
(same thing for data)argv0
. For instance, if argv0
is /path/to/build/sdk/bin/foo
, we can assume the prefix is /path/to/build/sdk
.qi::path documentation.
The API of qi::path always make sure that:
For this to work, we must make sure that
Have a look on the API of qi::path for more details
Writing a configuration file is very different from reading one.
Let's assume the foo
executable want to make sure that SPAM=42
in foo.cfg
.
Here is how it works:
foo.cfg
foo.cfg
is foundfoo.cfg
filefoo.cfg
file.You can see that we ask for a list of paths when reading, but that we always write to one file.
Let's go through these steps again, assuming foo
is installed in /usr/bin/foo
, and foo.cfg
in /usr/share/foo/foo
.cfg, and that there is nothing else on the machine where foo
is running.
foo.cfg
using qi::path::getConfigurationPaths [~/.config/foo/foo.cfg, /usr/share/foo/foo.cfg]
.config/foo/foo.cfg does not exist, we read /usr/share/foo/foo
.cfg SPAM=42
to ~/
.config/foo/foo.cfgThen each time a piece of code will ask for the foo.cfg
path, it will get a list starting with ~/
.config/foo/foo.cfg, so we are sure the setting SPAM=42
will be used.
/* * Copyright (c) 2012 Aldebaran Robotics. All rights reserved. * Use of this source code is governed by a BSD-style license that can be * found in the COPYING file. */ #include <iostream> #include <fstream> #include <vector> #include <qi/os.hpp> #include <qi/path.hpp> #include <qi/qi.hpp> #include <boost/locale.hpp> #include <boost/filesystem.hpp> #include <locale> int main(int argc, char *argv[]) { // Set the global locale to loc std::locale::global(boost::locale::generator().generate("")); // Make boost.filesystem use it boost::filesystem::path::imbue(std::locale()); // Get the prefix name from argv0 std::cout << "argv0 is: " << argv[0] << std::endl; // Get the prefix name from argv0 // Performs various initializations. // This is usually called by qi::init() qi::init(argc, argv); // Get sdk prefix std::cout << "SDK prefix is: " << qi::path::sdkPrefix() << std::endl; // First argument is the name of the application, used // to build various paths later. std::string fooCfgPath = qi::path::findConf("foo", "foo.cfg"); if (fooCfgPath == "") { std::cerr << "Could not find foo.cfg" << std::endl; std::cerr << "Looked in: " << std::endl; std::vector<std::string > configPaths = qi::path::confPaths("foo"); std::vector<std::string>::const_iterator it; for (it = configPaths.begin(); it != configPaths.end(); ++it) { std::cerr << "\t" << *it << std::endl; } } else { std::cout << "Found foo.cfg: " << fooCfgPath << std::endl; std::cout << "Contents: " << std::endl; char buf[250]; std::ifstream ifs; // Set stream to the right charset ifs.imbue(std::locale()); ifs.open(fooCfgPath.c_str(), std::fstream::in); while (! ifs.eof()) { ifs.getline(buf, 250); std::cout << buf << std::endl; } ifs.close(); } // ... Write back the configuration to userCfgPath std::string userCfgPath = qi::path::userWritableConfPath("foo", "foo.cfg"); std::cout << "Writing config file to: " << userCfgPath << std::endl; std::ofstream ofs(userCfgPath.c_str(), std::fstream::out | std::fstream::trunc); ofs << "Hi, this is foo.cfg" << std::endl; ofs.close(); return 0; }
qi::path documentation.