Did the Inno Setup website fail to document the #define directives or did I miss that somewhere? Is it permissible to define using defined strings and concatenate them?
#define MyApp ABC
#define MyAppVersion 1.2.1
#define MyFolder ? ; what is the right syntax here to concatenate
; the two previously defined strings?
Here is the section of help concerning defines:
http://www.jrsoftware.org/ispphelp/index.php?topic=define
Regarding your example:
#define MyApp "ABC"
#define MyAppVersion "1.2.1"
#define MyFolder MyApp + MyAppVersion
#define MyFolder1 MyApp + "Some other string"
Related
I need to use strerror_r to translate error numbers into human readable messages compiled with g++ on Linux Debian Bullseye. The man page notes:
int strerror_r(int errnum, char *buf, size_t buflen);
/* XSI-compliant */
char *strerror_r(int errnum, char *buf, size_t buflen);
/* GNU-specific */
strerror_r():
The XSI-compliant version is provided if:
(_POSIX_C_SOURCE >= 200112L) && ! _GNU_SOURCE
Otherwise, the GNU-specific version is provided.
We have two different types of the return value: int or char* depending on the version defined by _POSIX_C_SOURCE. I have this small test program:
~$ cat strerror_r.c
#include <string.h>
#include <stdio.h>
// #define _POSIX_C_SOURCE 200112L
// #undef _GNU_SOURCE
#define ERROR_BUFFER_LEN (size_t)256
int main(int argc, char **argv)
{
#if _POSIX_C_SOURCE < 200112L
char* ret;
#else
int ret;
#endif
char errorBuffer[ERROR_BUFFER_LEN];
int errno;
errno = 0;
ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
fprintf(stderr, "Error message by pointer = '%s'\n", ret);
fprintf(stderr, "Content of errorBuffer = '%s'\n", errorBuffer);
return 0;
}
If I compile it with gcc everything is as expected:
$ gcc strerror_r.c && ./a.out; rm a.out
Error message by pointer = '(null)'
Content of errorBuffer = 'Success'
If I compile it with g++ I get this:
$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
24 | ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| char*
rm: cannot remove 'a.out': No such file or directory
If I try to force the needed version by uncommenting
#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE
I get:
$ g++ strerror_r.c && ./a.out; rm a.out
strerror_r.c:7: warning: "_POSIX_C_SOURCE" redefined
7 | #define _POSIX_C_SOURCE 200112L
|
In file included from /usr/include/x86_64-linux-gnu/bits/libc-header-start.h:33,
from /usr/include/string.h:26,
from strerror_r.c:3:
/usr/include/features.h:281: note: this is the location of the previous definition
281 | # define _POSIX_C_SOURCE 200809L
|
strerror_r.c: In function ‘int main(int, char**)’:
strerror_r.c:24:21: error: invalid conversion from ‘char*’ to ‘int’ [-fpermissive]
24 | ret = strerror_r(errno, errorBuffer, ERROR_BUFFER_LEN);
| ~~~~~~~~~~^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| |
| char*
rm: cannot remove 'a.out': No such file or directory
What I'm missing here? Why g++ does not compile the default thread save version of strerror_r? I need that version. How can I fix it?
Reference
Feature Test Macros
You need to specify the #define and #undef directives before you include any header files, so the first few lines should look like this:
#define _POSIX_C_SOURCE 200112L
#undef _GNU_SOURCE
#include <string.h>
#include <stdio.h>
That's because those header files or internal header files they include need those values defined to choose the proper variant. If you define them after including the headers, the headers don't see the right values and they don't include the version you want.
Often people specify these values on the command like with the -D and -U arguments so they are always specified before header files are included.
I often use the recursesubdirs flag to traverse through a number of sub directories and extract a specific file or type of file without having to explicitly refer to each file individually. Example:
Source: C:\kh25\dependencies\*.dll; DestDir: {app}; Flags: recursesubdirs
This creates the exact same directory structure in my destination {app} path as the source from where the DLL was initially retrieved from. For example if I retrieved a DLL from C:\kh25\dependencies\test above then it would place that DLL in the {app}\test path.
This behaviour can be modified by doing this:
Source: C:\kh25\dependencies\test\*.dll; DestDir: {app}; Flags: recursesubdirs
But obviously this means I would have to reference each sub directory in dependencies individually.
So the $64,000 question is how can I prevent the same directory from being recreated in the destination without having to explicitly reference the source directory?
Use Inno Setup preprocessor to generate the entries for the [Files] section.
One possible (and relatively nice and simple) solution is using a recursive macro like:
#pragma parseroption -p-
#define FileEntry(Source) \
"Source: " + Source + "; DestDir: {app}\n"
#define ProcessFile(Source, FindResult, FindHandle) \
FindResult \
? \
Local[0] = FindGetFileName(FindHandle), \
Local[1] = Source + "\\" + Local[0], \
(Local[0] != "." && Local[0] != ".." \
? (DirExists(Local[1]) ? \
ProcessFolder(Local[1]) : FileEntry(Local[1])) \
: "") + \
ProcessFile(Source, FindNext(FindHandle), FindHandle) \
: \
""
#define ProcessFolder(Source) \
Local[0] = FindFirst(Source + "\\*", faAnyFile), \
ProcessFile(Source, Local[0], Local[0])
#pragma parseroption -p+
#emit ProcessFolder("C:\kh25\dependencies")
Though this solution has its limit and may crash the preprocessor with large number of files or deep directory structure (works ok for thousands of files).
Inspired by the answer by #Zlatko Karakaš to Use Inno Setup PreProcessor to get the files and size of the source path and its subdirs.
More reliable (and ugly and complex) solution is using a user defined procedures. It's complicated because the preprocessor lacks a support for parameters of user-defined procedures.
[Files]
#define FindHandle
#define FindResult
#dim InnerMask[65536]
#define InnerMask[0] ""
#sub ProcessFoundFile
#define InnerFileName FindGetFileName(FindHandle)
#define fileName InnerMask[InnerMaskWorkPosition] + InnerFileName
#if InnerFileName!="." && InnerFileName!=".."
#if DirExists(FileName)
#define Public InnerMask[InnerMaskPosition] FileName+"\"
#define Public InnerMaskPosition InnerMaskPosition + 1
#else
Source: {#FileName}; DestDir: {app}
#endif
#endif
#endsub
#sub ProcessInnerMaskPosition
#for { \
FindHandle = FindResult = \
FindFirst(InnerMask[InnerMaskWorkPosition]+"*", faAnyFile); \
FindResult; FindResult = FindNext(FindHandle)} ProcessFoundFile
#if FindHandle
#expr FindClose(FindHandle)
#endif
#endsub
#sub CollectFiles
#define Public InnerMaskPosition 1
#define Public InnerMaskWorkPosition 0
#for { \
InnerMaskWorkPosition = 0; InnerMaskWorkPosition < InnerMaskPosition; \
InnerMaskWorkPosition++} \
ProcessInnerMaskPosition
#undef Public InnerMaskPosition
#undef Public InnerMaskWorkPosition
#endsub
#expr InnerMask[0]="C:\kh25\dependencies\"
#expr CollectFiles
The recursive scan function taken from the answer by #René Martin to Use Inno Setup PreProcessor to get the files and size of the source path and its subdirs.
Add a SaveToFile call at the very end of your Inno Setup script too see, what the preprocessor generates:
#expr SaveToFile(AddBackslash(SourcePath) + "Preprocessed.iss")
See Inno Setup: How do I see the output (translation) of the Inno Setup Preprocessor?
My answer to this question explains the differences between the two approaches taken above:
Can Inno Setup Preprocessor be used to build a duplicated set of custom messages?
I'm attempting to create a string with spaces for my GUI title with some macros, I have this resource.h:
#define QUOTE(s) #s
#define xstr(s) QUOTE(s)
#define PACKAGE_NAME "SoundTest"
#define PACKAGE_VERSION_MAYOR 1
#define PACKAGE_VERSION_MINOR 8
#define PACKAGE_VERSION xstr(PACKAGE_VERSION_MAYOR.PACKAGE_VERSION_MINOR)
#define PACKAGE_STRING xstr(PACKAGE_NAME PACKAGE_VERSION)
The above produce this output in my window title: "SoundTest" "1.8" (with quotes);
I want this output: SoundTest 1.8 (without quotes). Any ideas?
PACKAGE_NAME already has quotes in it:
#define PACKAGE_NAME "SoundTest"
So if you stringify PACKAGE_NAME, you'll stringify the quotes as well, resulting in something like "\"SoundTest\"". (Remember that the C preprocessor just works with characters. It does not understand C datatypes.)
Fortunately, C lets you concatenate string literals just by writing them one after another, so that, for example, "SoundTest" " " "1.8" is a single string literal, just as though it had been written "SoundTest 1.8". You can use that to your advantage here:
#define PACKAGE_VERSION xstr(PACKAGE_VERSION_MAYOR.PACKAGE_VERSION_MINOR)
#define PACKAGE_STRING PACKAGE_NAME " " PACKAGE_VERSION
Does this work, its not the neatest solution though ?
#define PACKAGE_NAME SoundTest
#define PACKAGE_VERSION_MAYOR 1
#define PACKAGE_VERSION_MINOR 8
// not using this actually
#define PACKAGE_VERSION xstr(PACKAGE_VERSION_MAYOR.PACKAGE_VERSION_MINOR)
#define PACKAGE_STRING xstr(PACKAGE_NAME PACKAGE_VERSION_MAYOR.PACKAGE_VERSION_MINOR)
I call ISCC /DENABLE_SIGNING=1 MyFile.iss, and in MyFile.iss I have:
#if ENABLE_SIGNING == 1
SignedUninstaller=yes
SignTool=mysigntool
#endif
ISPP fails with an error exactly at the line with #if ENABLE_SIGNING == 1:
[ISPP] Operator not applicable to this operand type.
But if I've defined ENABLE_SIGNING in the MyFile.iss instead, it goes fine. This code passes without errors:
#define ENABLE_SIGNING 1
#if ENABLE_SIGNING == 1
SignedUninstaller=yes
SignTool=mysigntool
#endif
Edit
Also, there is another problem, when I use /DENABLE_SIGNING=0, testing #if ENABLE_SIGNING succeeds, while if I use #define ENABLE_SIGNING 0, the check fails (meaning evaluates to false), as it should.
From some tests I've ran right now it seems the command line interpreted preprocessor takes the define default values as strings. So when you modify your condition this way, it will work properly:
; just for case when you wouldn't run ISCC from command line
#ifndef ENABLE_SIGNING
#define ENABLE_SIGNING "1"
#endif
[Setup]
AppName=My Program 1
AppVersion=1.5
DefaultDirName={pf}\My Program
#if ENABLE_SIGNING == "1"
SignedUninstaller=yes
SignTool=mysigntool
#endif
Lines starting with sign '%' should be passed as is in output file,
but is such lines have some CPP macros, those macros are expanded as well:
Source (test.x):
#ifdef ONE
#warning "ONE is defined"
#else
#warning "NO ONE!!!!!1111"
#endif
%
% hello, ONE
%
Running rpcgen:
# rpcgen test.x -DONE
test.x:2:2: warning: #warning "ONE is defined" [-Wcpp]
test.x:2:2: warning: #warning "ONE is defined" [-Wcpp]
test.x:2:2: warning: #warning "ONE is defined" [-Wcpp]
test.x:2:2: warning: #warning "ONE is defined" [-Wcpp]
Result (test.h):
/*
* Please do not edit this file.
* It was generated using rpcgen.
*/
#ifndef _TEST_H_RPCGEN
#define _TEST_H_RPCGEN
#include <rpc/rpc.h>
#ifdef __cplusplus
extern "C" {
#endif
hello, 1
#ifdef __cplusplus
}
#endif
#endif /* !_TEST_H_RPCGEN */
So "ONE" is replaced with "1", but it is desirable leave it as is
(consider "#ifdef ONE" in resulting test.h)
It there any way to aviod it?
So, I have a workaroud with CPP wrapper:
somedir/cpp <- wrapped which undefines problematic macros. For example:
#!/bin/sh
exec /usr/bin/cpp -U_LP64
Run rpcgen as rpcgen -Y somedir