I am trying to find out the best approach providing special build stubs (Special Builds) for the Debian project. One of my goals is to keep the maintenance burden at a minimum.
My approach is based on the discussions in the bug reports #432713 and #942396.
So my proposal would be to make the makensis executable generic enough to cope
with the default and special builds. makensis could be instructed to select the respective stubs via an environment variable and the compilation specifics of the special builds could be handled by defines set at the command line or in the (/etc/)nsisconf.nsh file.
In order to have something more tangible I am going to outline how I would do it.
Index: Source/build.cpp =================================================================== --- Source/build.cpp (revision 7127) +++ Source/build.cpp (working copy) @@ -407,8 +407,13 @@ includes_dir += PLATFORM_PATH_SEPARATOR_STR _T("Include"); include_dirs.add(includes_dir.c_str(),0); - stubs_dir = nsis_dir; - stubs_dir += PLATFORM_PATH_SEPARATOR_STR _T("Stubs"); + dir = _tgetenv(_T("NSISSTUBSDIR")); + if (dir) { + stubs_dir = dir; + } else { + stubs_dir = nsis_dir; + stubs_dir += PLATFORM_PATH_SEPARATOR_STR _T("Stubs"); + } if (set_compressor(_T("zlib"), false) != PS_OK || set_target_architecture_data() != PS_OK) {
Index: Source/exehead/fileform.h =================================================================== --- Source/exehead/fileform.h (revision 7127) +++ Source/exehead/fileform.h (working copy) @@ -180,10 +180,6 @@ EW_WRITEUNINSTALLER, // WriteUninstaller: 3 [name, offset, icon_size] #endif -#ifdef NSIS_CONFIG_LOG - EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate] -#endif - #ifdef NSIS_CONFIG_COMPONENTPAGE EW_SECTIONSET, // SectionSetText: 3: [idx, 0, text] // SectionGetText: 3: [idx, 1, output] @@ -207,6 +203,8 @@ EW_FGETWS, // FileReadUTF16LE: 4 [handle, output, maxlen, ?getchar:gets] #endif//NSIS_SUPPORT_FILEFUNCTIONS #endif + + EW_LOG, // LogText: 2 [0, text] / LogSet: [1, logstate] }; #pragma pack(push, 1) // fileform.cpp assumes no padding/alignment Index: Source/lang.cpp =================================================================== --- Source/lang.cpp (revision 7127) +++ Source/lang.cpp (working copy) @@ -309,12 +309,12 @@ NLFRefs[i].iRef = 0; NLFRefs[i].iUnRef = 0; -#ifdef NSIS_CONFIG_LOG - if (i == NLF_NAME) { - NLFRefs[i].iRef++; - NLFRefs[i].iUnRef++; + if (definedlist.find(_T("NSIS_CONFIG_LOG"))) { + if (i == NLF_NAME) { + NLFRefs[i].iRef++; + NLFRefs[i].iUnRef++; + } } -#endif if (NLFStrings[i].eStaticID & INSTALL_STATIC) { set_uninstall_mode(0); Index: Source/script.cpp =================================================================== --- Source/script.cpp (revision 7127) +++ Source/script.cpp (working copy) @@ -1640,13 +1640,11 @@ { int k=line.gettoken_enum(1,_T("normal\0silent\0silentlog\0")); if (k<0) PRINTHELP() -#ifndef NSIS_CONFIG_LOG - if (k == 2) + if (k == 2 && !definedlist.find(_T("NSIS_CONFIG_LOG"))) { ERROR_MSG(_T("SilentInstall: silentlog specified, no log support compiled in (use NSIS_CONFIG_LOG)\n")); return PS_ERROR; } -#endif //~ NSIS_CONFIG_LOG SCRIPT_MSG(_T("SilentInstall: %") NPRIs _T("\n"),line.gettoken_str(1)); #ifdef NSIS_CONFIG_LICENSEPAGE if (k && HasUserDefined(NLF_LICENSE_DATA)) @@ -2050,9 +2048,9 @@ GET(IDD_DIR); SEARCH(IDC_DIR); SEARCH(IDC_BROWSE); -#ifdef NSIS_CONFIG_LOG - SEARCH(IDC_CHECK1); -#endif + if (definedlist.find(_T("NSIS_CONFIG_LOG"))) { + SEARCH(IDC_CHECK1); + } SAVE(IDD_DIR); } @@ -4764,26 +4762,25 @@ ERROR_MSG(_T("Error: %") NPRIs _T(" specified, NSIS_SUPPORT_REBOOT not defined.\n"), line.gettoken_str(0)); return PS_ERROR; #endif //~ NSIS_SUPPORT_REBOOT -#ifdef NSIS_CONFIG_LOG case TOK_LOGSET: - ent.which=EW_LOG; - ent.offsets[0]=1; - ent.offsets[1]=line.gettoken_enum(1,_T("off\0on\0")); - if (ent.offsets[1]<0) PRINTHELP() - SCRIPT_MSG(_T("LogSet: %") NPRIs _T("\n"),line.gettoken_str(1)); - return add_entry(&ent); case TOK_LOGTEXT: - ent.which=EW_LOG; - ent.offsets[0]=0; - ent.offsets[1]=add_string(line.gettoken_str(1)); - SCRIPT_MSG(_T("LogText \"%") NPRIs _T("\"\n"),line.gettoken_str(1)); - return add_entry(&ent); -#else - case TOK_LOGSET: - case TOK_LOGTEXT: - ERROR_MSG(_T("Error: %") NPRIs _T(" specified, NSIS_CONFIG_LOG not defined.\n"), line.gettoken_str(0)); - return PS_ERROR; -#endif //~ NSIS_CONFIG_LOG + if (!definedlist.find(_T("NSIS_CONFIG_LOG"))) { + ERROR_MSG(_T("Error: %") NPRIs _T(" specified, NSIS_CONFIG_LOG not defined.\n"), line.gettoken_str(0)); + return PS_ERROR; + } else if (which_token == TOK_LOGSET) { + ent.which=EW_LOG; + ent.offsets[0]=1; + ent.offsets[1]=line.gettoken_enum(1,_T("off\0on\0")); + if (ent.offsets[1]<0) PRINTHELP() + SCRIPT_MSG(_T("LogSet: %") NPRIs _T("\n"),line.gettoken_str(1)); + return add_entry(&ent); + } else { + ent.which=EW_LOG; + ent.offsets[0]=0; + ent.offsets[1]=add_string(line.gettoken_str(1)); + SCRIPT_MSG(_T("LogText \"%") NPRIs _T("\"\n"),line.gettoken_str(1)); + return add_entry(&ent); + } #ifdef NSIS_CONFIG_COMPONENTPAGE case TOK_SECTIONSETTEXT: ent.which=EW_SECTIONSET;
I moved the EW_LOG operation code to the end in order to be compatible with the standard stubs (Rebuild of the special stubs are required).
The tests for the NSIS_CONFIG_LOG define via definedlist.find are not ideal. A better approach would be to query the NSIS_CONFIG_LOG define once, have it cached in a member variable and query this variable via a member function.
makensis including plugins and stubs would be build as usual. The advanced logging stubs would be build with
scons PREFIX=/usr PREFIX_CONF=/etc STRIP_CP=no NSIS_CONFIG_LOG=yes UNICODE=yes SKIPUTILS=all XGCC_W32_PREFIX=i686-w64-mingw32- TARGET_ARCH=x86 PREFIX_DEST=/tmp/nsis-common install-stubs
Thereafter the resulting makensis can deal with the default stubs and the advanced logging stubs.
I used the following logging.nsi script to test the advanced logging stubs:
Unicode true Name Logging Page Directory Page InstFiles Function .onInit StrCpy $INSTDIR $EXEDIR FunctionEnd Section "-hidden" LogSet on MessageBox MB_OK "Hello World!" SectionEnd
Makensis is run as the following
NSISSTUBSDIR=/tmp/nsis-common/usr/share/nsis/Stubs makensis -DNSIS_CONFIG_LOG logging.nsi
This installer does its logging to $INSTDIR\install.log.
logging set to 1 MessageBox: 0,"Hello World!" RMDir: RemoveDirectory invalid input("")
Index: Source/exehead/config.h =================================================================== --- Source/exehead/config.h (revision 7127) +++ Source/exehead/config.h (working copy) @@ -23,6 +23,12 @@ #include <nsis-sconf.h> +#define NSIS_LARGE_MAX_STRLEN 8192 +#if NSIS_MAX_STRLEN > NSIS_LARGE_MAX_STRLEN + #undef NSIS_LARGE_MAX_STRLEN + #define NSIS_LARGE_MAX_STRLEN NSIS_MAX_STRLEN +#endif + #ifndef NSIS_CONFIG_VISIBLE_SUPPORT #ifdef NSIS_CONFIG_LICENSEPAGE #undef NSIS_CONFIG_LICENSEPAGE Index: Source/makenssi.cpp =================================================================== --- Source/makenssi.cpp (revision 7127) +++ Source/makenssi.cpp (working copy) @@ -543,7 +543,12 @@ build.INFO_MSG(_T("Command line defined: \"%") NPRIs _T("\"\n"),p); v=_tcsstr(s,_T("=")); if (v) *v++=0; - build.define(s,v?v:_T("")); + if (_tcsicmp(_T("NSIS_MAX_STRLEN"), s)) { + build.define(s,v?v:_T("")); + } else if (_ttol(v) <= NSIS_LARGE_MAX_STRLEN) { + build.definedlist.del(s); + build.definedlist.add(s, v); + } free(s); } else if (S7IsChEqualI('x',swname[0]) && swname[1])
This code would allow overwriting of the NSIS_MAX_STRLEN define from the command line. Further changes are required to modify. For example increasing the size of variables to NSIS_LARGE_MAX_STRLEN but only output variables of NSIS_MAX_STRLEN size as required by the respective stubs.
Please provide your feedback, thoughts and improvements.
Our goal should be to provide all the stubs by default. Ideally we would be able to tag the stub somehow so we can tell the stringsize and logging feature, possibly by having a PE string resource that makensis removes after reading the stub.