I'm writing a Qt app that runs in Linux. I need to write a file to:
"$XDG_CONFIG_DIRS/whatever"/ "$HOME/whatever"
How do I resolve the environment variables ## Heading ##in my code?
Using nothing but plain library functions, you use getenv() to look up the value of environment variables:
const char *dirs = getenv("XDK_CONFIG_DIRS");
This will return NULL if the variable was not set in the environment, so make sure your code handles this case.
You'll have to do the "interpolation" of the variable values into the rest of the text yourself, in that case.
Not sure if Qt provides a wrapper or something more high-level that can do the interpolation for you, I haven't worked with Qt.
getenv, as already mentioned, if you really only target Linux. If you want it portable to Non-Unix platforms, you should use qgetenv() or QProcessEnvironment::systemEnvironment().value(QLatin1String("XDG_CONFIG_DIRS")). In general, it's good practice to use the portable Qt way.
Related
Used Scons version: 3.0.1 (for historic reasons)
I want to add a command-line build variable in my Scons script which is not limited by which values it expects. Both EnumVariable and ListVariable require you to provide a list of allowed values or elements.
I want a variable that (just like a C++ define can be passed to g++ via -Dfoo=bar (or at least -Dfoo_bar) ) can be passed to the Scons script.
Anything like
scons my_define=foo_bar
or
scons my_define=foo=bar,gnarl=argl
or
scons my_define=foo my_define=bar
would work.
I did not find anything like that in the user guide or searching via Google.
Is this possible? If yes, how?
Yes. It's in the users guide at
https://scons.org/doc/production/HTML/scons-user.html#idp140637539360912
While there are validated variable types provided by the various vars.Add*() methods. You can have a non-validated variable by just using plain vars.Add()
Here's an example from the manpage.
vars.Add('CC', help='The C compiler')
I want to write a pester test, that works both on Linux and on Windows. The test creates vscode snippets, and I want to be sure it creates them in the correct place.
I want to make my test as generic as possible, and test automatically at the right place according the OS.
I know on Windows I could use $env:AppDAta but that variable doesn't exists on linux.
what could I use instead, which would work on both platforms.
Cheers!
You cannot rely on environment variables across platforms, but .NET Core does make known / special folders available in a cross-platform manner via its [Environment]::GetFolderPath() method.
Not all locations defined there in the abstract are available on all platforms, but ApplicationData is:
[Environment]::GetFolderPath('ApplicationData')
For username jdoe, the above yields the following paths:
Windows: C:\Users\jdoe\AppData\Roaming (equivalent of: $env:APPDATA)
Linux: /home/jdoe/.config (equivalent of: $HOME/.config)
macOS: /Users/jdoe/.config (equivalent of: $HOME/.config)
Also note this proposal on GitHub, which suggests exposing these folders in a more PowerShell-idiomatic way via a new namespace $sf: (for special folder), so that $sf:ApplicationData would be the equivalent of the above command.
If you'd like to see that implemented, make your voice heard there. Even a simple "thumbs up" helps.
Im trying to accomplish a twincat 3 library which does things using global constants defined in the main project, like creating arrays the size of those constants and cycling trough them. However I've been unsuccessful and I wonder if this can be done. I just get this error "Error 4 Border 'cPassedConstant' of array is no constant value" when I try to build the main project. The error comes from the array defined in the library.
I've tried making a GVL with a constant of the same name to the library and then setting the "external implementation" property true but that does not help.
My goal here is to make a IO management library with filtering and such. And then I could just add it to the main project and define some constants like "cDigitalIputsCount","cAnalogInputCount" and so on.
Maybe you can get along with the new ARRAY[*] feature instead, although it is still very limited. There is no other way than to define the constant in the library.
The library concept is the same as in other environments. A library provides you reusable components. Your main project depends on the library and not the other way around. Therefore your library cannot know a thing about the project where it is used.
A confusing thing in TwinCat3 is, that you can build projects successful with programming errors inside. The TwinCat3 compiler allows broken code inside a project as long as it is not called. Therefore when you ship libraries you should always use "Check all objects".
You should check Beckhoff's feature called Parameter List. By adding a parameter list to the library project, you can re-define library constants in the project that uses the library. The definition happens in the library manager.
Image from Beckhoff's site:
I think that should do it. Of course, the other option is to use the ARRAY[*] option, which is awesome too (for a PLC programming world). The problem with parameter lists is that it is a project-wide re-definition. Using the ARRAY[*] allows the size be changed dynamically.
I would suggest using a variable length ARRAY[*], as explained in the link below (and also in the Beckhoff/Infosys, section DataTypes/Array).
The point is that you should declare the ARRAY[1..cAINs] of FB_AnalogIO in your main program (it knows the FB_AnalogIO from your analog library and can declare it with a constant size).
The PRG_IO should then be changed to either a function or function block, so that it accepts the ARRAY[*] as a VAR_IN_OUT without knowing the exact size.
https://stefanhenneken.wordpress.com/2016/09/27/iec-61131-3-arrays-with-variable-length/
I have some non-accessible code that I call, that does dlopen("lib.so", RTLD_LOCAL).
The problem is that I need to control the search path of dlopen(). The answer to this problem is quite typically "set LD_LIBRARY_PATH", but I don't know the actual path to set until after application startup, so I can't put a wrapper script that sets it and then invokes my application.
According to the documentation of ld.so and of dlopen, LD_LIBRARY_PATH is only examined at application startup. If you change it afterwards inside the application with setenv, it won't change the lookup list of dlopen().
I know that specifying the full path to dlopen() would be a strategy, but I don't have access to that dlopen call, so this option is also not possible.
Am I out of options or is there some magic strategy I can't find?
I believe it is not easily possible.
However, if you are crazy enough to patch ld.so from its source code, you might do something.
Maybe you could use some LD_PRELOAD trick.
But if it is a matter of finding which exact file is dlopen-ed, why don't you strace(1) your program to understand which files are mmap-ed?
You can also use pmap or simply cat /proc/$(pidof your-program)/maps
If you can change some lines of source code, consider dladdr(3) to find out where is some dlsym-ed function... And you might also use dl_iterate_phdr(3)
If your LD_LIBRARY_PATH is relative to your application root - you can use wrapper script, which will extract path to itself using $(dirname $0) and set up correct LD_LIBRARY_PATH.
Another trick (but it's not a good idea to do so) is to provide your own lib.so that will be just a proxy to actual lib.so. You can initialize all references on your proxy library load using library init functionality. Please refer to this question.
I have a custom environment set up for my tests:
test_env = env.Clone()
test_env.Append(LIBS=['boost_unit_test_framework'])
But for one of my tests, I want to link against an additional library:
test_env.Program('foo_tests',
source='foo/tests.cpp',
LIBS=['extralib'],
LIBPATH=['.'])
Sadly this overrides the LIBS from the environment, when I'd like it to just add to it. Is there a better (i.e. more canonical) way to do this than LIBS=test_env['LIBS'] + ['extralib']?
Specifying a new value for an environment variable in a Builder call (like Program) is always interpreted as an "override". So there is no way around compiling the full replacement value, as you did in your example above.
The other option would be to Clone the environment "test_env" again, and then use Append to add the "extralib" to LIBS...
It's possible to do it like this:
test_env.Program('foo_tests',
source='foo/tests.cpp',
LIBS=['$LIBS', 'extralib'],
LIBPATH=['$LIBPATH', '.'])
SCons is clever enough to properly expand the variable into a list there.