构建 x64 NSIS(使用 VS2012)

Building x64 NSIS (using VS2012)

我正在创建我的应用程序的纯 x64 版本。为此,我还需要一个 x64 安装程序。我在网上看到 NSIS 代码确实支持 x64,但由于它们不分发我需要从源代码构建的 x64 版本(包括所有 plugins/etc)。

我已经能够使用 Python 2.7/SCons 3.1.1/VS 2012/Zlib 1.2.7 从 x86 源代码构建 NSIS (v3.0.4)。

scons ZLIB_W32=C:\Source\zlib-1.2.7

但是当我将 TARGET_ARCH=amd64 添加到 scons 命令时,

scons ZLIB_W32=C:\Source\zlib-1.2.7 TARGET_ARCH=amd64

没用。最初它构建但没有 link 因为 zlib 仍然是 x86。

C:\Source\zlib-1.2.7\lib\zdll.lib : warning LNK4272: library machine type 'x86' conflicts with target machine type 'x64'

然而,在重建 zlib1.dll(使用 VS2012)成为 x64 之后(dumpbin 证实了这一点)

我现在收到一个找不到 zlib 的错误

scons ZLIB_W32=C:\Source\zlib-1.2.7 TARGET_ARCH=amd64
scons: Reading SConscript files ...
WARNING: VER_PACKED not set, defaulting to 0x03003666!
Delete("nsis-18-Nov-2019.cvs")
Delete(".instdist")
Delete(".test")
Using Microsoft tools configuration (14.2)
Checking for memset requirement... (cached) yes
Checking for memcpy requirement... (cached) yes
Checking for C library gdi32... (cached) yes
Checking for C library user32... (cached) yes
Checking for C library pthread... (cached) no
Checking for C library iconv... (cached) no
Checking for C library shlwapi... (cached) yes
Checking for C library oleaut32... (cached) yes
Checking for C library version... (cached) yes
Checking for C library zdll... no
Checking for C library z... no
zlib (win32) is missing!

请注意,我已确保目录结构在 x64 构建中匹配,因此存在以下文件:

C:\Source\zlib-1.2.7\zlib1.dll
C:\Source\zlib-1.2.7\lib\zlib1.lib
C:\Source\zlib-1.2.7\include\zconf.h
C:\Source\zlib-1.2.7\include\zlib.h

我确实想到我要告诉 scons 寻找 x86 zlib(因此 ZLIB_W32 中的 W32)但我没有看到告诉 scons 寻找 x64 zlib 的选项-h 输出。

我错过了什么?

-更新 1- 我正在取得进步,但还没有走出困境。我发现我的构建存在几个问题。 #1,我实际上并没有像我想的那样使用 VS2012(我安装了几个版本)。请参阅上面 scons 输出显示 14.0 (VS2019) 的位置。哎呀。不幸的是,简单地在我的命令行中添加一个 MSVC_VERSION=11.0 并没有解决它。似乎 nsis 项目没有将其传递给 scons。我能弄清楚如何做到这一点的唯一方法是修改 nsis SConstruct 文件:

######################################################################
#######  Build Environment                                         ###
######################################################################

path = ARGUMENTS.get('PATH', '')
toolset = ARGUMENTS.get('TOOLSET', '')
arch = ARGUMENTS.get('TARGET_ARCH', 'x86')

if toolset and path:
    defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path}, TOOLS = toolset.split(',') + ['zip'])
else:
    if path:
        defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path})
    if toolset:
        defenv = Environment(TARGET_ARCH = arch, TOOLS = toolset.split(',') + ['zip'])
if not toolset and not path:
    defenv = Environment(TARGET_ARCH = arch)

Export('defenv')

至:

######################################################################
#######  Build Environment                                         ###
######################################################################

path = ARGUMENTS.get('PATH', '')
toolset = ARGUMENTS.get('TOOLSET', '')
arch = ARGUMENTS.get('TARGET_ARCH', 'x86')
vs_version = ARGUMENTS.get('MSVC_VERSION', '')

if toolset and path:
    defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path}, TOOLS = toolset.split(',') + ['zip'], MSVC_VERSION = vs_version)
else:
    if path:
        defenv = Environment(TARGET_ARCH = arch, ENV = {'PATH' : path}, MSVC_VERSION = vs_version)
    if toolset:
        defenv = Environment(TARGET_ARCH = arch, TOOLS = toolset.split(',') + ['zip'], MSVC_VERSION = vs_version)
if not toolset and not path:
    defenv = Environment(TARGET_ARCH = arch, MSVC_VERSION = vs_version)

Export('defenv')

现在我的构建输出正确识别为 VS2012:

C:\Source\nsis\nsis-code-r7069-NSIS-tags-v304>scons ZLIB_W32=C:\Source\zlib MSVC_VERSION=11.0
scons: Reading SConscript files ...
WARNING: VER_PACKED not set, defaulting to 0x03003666!
Delete("nsis-19-Nov-2019.cvs")
Delete(".instdist")
Delete(".test")
Using Microsoft tools configuration (11.0)
Checking for memset requirement... (cached) yes
<snip>

似乎应该有更好的方法来实现这一点,但我(还)对 scons 或 nsis 的使用还不够熟悉,无法提交 PR 来解决这个问题。也可能它已经存在,只是我不够聪明(还)找不到它。

现在开始构建 x64 nsis。非常感谢@Anders 缩小了需要的文件范围,并感谢@bdbaddog 建议查看 scons config.log,我发现我在构建它时错误地命名了 zlib.dll lib 文件x64。将输出库更改为

C:\Source\zlib-1.2.7\lib\zdll.lib

它至少尝试构建但在 linking...

时失败

-编辑以更新 1- 之前出现的所有 linking 错误都是我昨天遇到的一个糟糕的兔子洞。不确定这是由于 scons 在某处留下一些临时文件还是 VS 这样做或我只是愚蠢但今天当我开始尝试追踪 linking 错误时我无法重现它们(有一台机器昨天重新启动,谁知道 locked/cached 到那时可能是什么)。

-更新 2- 此更新从更新 1 中删除了所有误导性废话。当前情况是 x64 NSIS 构建(同时使用我的 zlib-1.2.7-amd64 构建和 NSIS 上的官方 NSIS zlib-1.2.8-amd64 预构建二进制文件wiki) 在 linking 失败并出现同样的错误:

System.obj : error LNK2019: unresolved external symbol CallProc2 referenced in function Call
build\urelease\System\amd64-unicode\System.dll : fatal error LNK1120: 1 unresolved externals
scons: *** [build\urelease\System\amd64-unicode\System.dll] Error 1120
scons: building terminated because of errors.

到目前为止,我还没有弄清楚 CallProc2 是什么,但我认为这意味着 zlib 在这里不再有问题。

-更新 3- 感谢@Anders 的指导,因为我真的对 Callproc 问题感到困惑,CallProc2 方法与系统插件隔离,并且是由于它没有正确构建而引起的。下面的评论中有一些讨论试图找到原因,但现在,我只是排除了那个插件,以便在回到这个之前进入一个可以工作的系统。

现在,scons 构建完成并生成 x64 二进制文件。

C:\Source\nsis\build\urelease\makensisw\>dumpbin /HEADERS ./makensisw.exe
Microsoft (R) COFF/PE Dumper Version 11.00.61030.0
Copyright (C) Microsoft Corporation.  All rights reserved.


Dump of file ./makensisw.exe

PE signature found

File Type: EXECUTABLE IMAGE

FILE HEADER VALUES
            8664 machine (x64)

但是,安装程序构建现在会导致以下错误:

scons dist-installer ZLIB_W32=C:\Source\zlib-1.2.8-x64 MSVC_VERSION=11.0
link /nologo /map /subsystem:console,5.01 /OUT:build\urelease\VPatch\Source\GenPat\GenPat.exe /LIBPATH:C:\Source\zlib-1.2.8-x64\lib zdll.lib build\urelease\VPatch\Source\GenPat\adler32.obj build\urelease\VPatch\Source\GenPat\Checksums.obj build\urelease\VPatch\Source\GenPat\ChunkedFile.obj build\urelease\VPatch\Source\GenPat\FileFormat1.obj build\urelease\VPatch\Source\GenPat\GlobalTypes.obj build\urelease\VPatch\Source\GenPat\main.obj build\urelease\VPatch\Source\GenPat\md5.obj build\urelease\VPatch\Source\GenPat\PatchGenerator.obj build\urelease\VPatch\Source\GenPat\POSIXUtil.obj
adler32.obj : error LNK2019: unresolved external symbol _adler32 referenced in function "unsigned long __cdecl Checksum::adler32(unsigned long,unsigned char const *,unsigned int)" (?adler32@Checksum@@YAKKPBEI@Z)
build\urelease\VPatch\Source\GenPat\GenPat.exe : fatal error LNK1120: 1 unresolved externals
scons: *** [build\urelease\VPatch\Source\GenPat\GenPat.exe] Error 1120

不幸的是,没有安装程序,我又迷路了。 x64 二进制文件 运行 但在尝试编译任何脚本时(我相信),我收到以下错误(请注意,我为此将 makensis 和 zlib1.dll 复制到同一目录中):

C:\Source>makensis.exe ./myapp.nsi
Error: reading stub "C:\Stubs\zlib-amd64-unicode"
Error initalizing CEXEBuild: error setting default stub

-更新 4- 在忽略系统插件后,我终于得到了一个可以成功运行的构建。这既适用于从源代码为 x64 编译 zlib,也适用于来自 NSIS wiki 的预构建版本(linked in @Anders answer below):

scons ZLIB_W32=C:\Source\zlib-1.2.8-x64 TARGET_ARCH=amd64 MSVC_VERSION=11.0 SKIPPLUGINS=System

并且我能够使用(自从我安装到 Program Files 以来从管理员启用的提示)部署到我的开发系统:

scons PREFIX="C:\Program Files (x86)\NSIS" install ZLIB_W32=C:\Source\zlib-1.2.8-x64 TARGET_ARCH=amd64 SKIPPLUGINS=System

不幸的是,您无法从此处构建 NSIS 安装程序 (dist-install),因为 NSIS 安装程序本身显然依赖于系统插件的使用。因此,除非您要在该机器上从头开始构建所有内容,否则这种情况不足以准备构建机器。

此外,我还没有摆脱困境,因为我还为我的安装程序使用了系统插件,所以我需要弄清楚为什么它不起作用。

但是,我能够使用上述设置编译并 运行 纯 x64 最小安装程序包:

# name the installer
OutFile "Installer.exe"

# default section start; every NSIS script has at least one section.
Section

# default section end
SectionEnd

以上直接来自 NSIS 文档。

我有

\zlib1.dll
\include\zconf.h
\include\zlib.h
\lib\libzdll.a
\lib\zdll.lib
\lib\zlib.lib

您可以获得 NSIS 的预构建 zlib here

过去我实际上使用 Process Monitor 来确定 SCons 正在寻找哪个文件,遗憾的是这似乎是最快的查找方法。

关于 CallProc2。将 "System" 添加到 SKIPPLUGINS 以解决此问题,以确保其他所有内容都能编译。 CallProc2 在 amd64 .S 文件中实现并被 system.c 使用。您需要正确检测到 64 位 Microsoft 汇编程序才能构建 .S 文件。

如果只需要编译一次NSIS就可以作弊;打开 Visual Studio 命令提示符并执行 ml64.exe /c Call-amd64.S,然后将 .obj 文件复制到与 system.obj 和 运行 Scons 相同的构建目录。

要正确执行此操作,您需要调查 Scons 不编译 .S 文件的原因。可能是配置问题或相关 Sconscript 文件中的错误。

我的环境:

  • cl.exe: Microsoft (R) C/C++ Optimizing Compiler Version 19.24.28316 for x64
  • nsis 版本:3.06.1
  • zlib: Zlib-1.2.8-win64-AMD64

我修改了SCons/Tool/masm.py

C:\miniconda3\Lib\site-packages\SCons-4.0.1-py3.7.egg\SCons\Tool>diff -c masm.old.py masm.py
*** masm.old.py Fri Oct 09 22:02:45 2020
--- masm.py     Fri Oct 09 21:58:06 2020
***************
*** 61,66 ****
--- 61,68 ----
          shared_obj.add_emitter(suffix, SCons.Defaults.SharedObjectEmitter)

      env['AS']        = 'ml'
+     if env.get('TARGET_ARCH')=='amd64':
+         env['AS']   = 'ml64'
      env['ASFLAGS']   = SCons.Util.CLVar('/nologo')
      env['ASPPFLAGS'] = '$ASFLAGS'
      env['ASCOM']     = '$AS $ASFLAGS /c /Fo$TARGET $SOURCES'

同时修改nsis-3.06.1-src\Contrib\System\SConscript如下:

C:\dev\nsis-3.06.1-src\Contrib\System>diff -c SConscript.old SConscript
*** SConscript.old      Fri Oct 09 22:06:31 2020
--- SConscript          Fri Oct 09 19:17:40 2020
***************
*** 4,9 ****
--- 4,10 ----
        Source/Buffers.c
        Source/Plugin.c
        Source/System.c
+       Source/Call-amd64.S
  """)

  libs = Split("""

然后C:\dev\nsis-3.06.1-src>scons TARGET_ARCH=amd64成功结束