Windows编译开源代码方法之关于lame.exe文件的测试及过程-程序员宅基地

技术标签: windows  microsoft  日志  

最终结果(PS:使用markdown不熟悉,记得在井号后面加个空格才能触发)


PS C:\Users\zjc20\source> cd .\lame-3.100\
PS C:\Users\zjc20\source\lame-3.100> nmake.exe .\Makefile.MSVC

Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

----------------------------------------------------------------------
building LAME featuring RH
+ ASM
+ MMX
using MS COMPILER
+ optimizing for Pentium II/III
+ using Single precision
----------------------------------------------------------------------
Pass GTK=YES to build the frame analyzer. (requires installed GTK)

libmp3lame\i386\cpu_feat.nas
'nasmw' is not recognized as an internal or external command,
operable program or batch file.
NMAKE : fatal error U1077: 'nasmw' : return code '0x1'
Stop.
PS C:\Users\zjc20\source\lame-3.100> copy .\configMS.h config.h
PS C:\Users\zjc20\source\lame-3.100> nmake -f .\Makefile.MSVC comp=msvc asm=no

Microsoft (R) Program Maintenance Utility Version 14.34.31937.0
Copyright (C) Microsoft Corporation.  All rights reserved.

----------------------------------------------------------------------
building LAME featuring RH
using MS COMPILER
+ optimizing for Pentium II/III
+ using Single precision
----------------------------------------------------------------------
Pass GTK=YES to build the frame analyzer. (requires installed GTK)
Pass ASM=YES to build the assembler optimizations

bitstream.c
encoder.c
fft.c
gain_analysis.c
id3tag.c
lame.c
newmdct.c
psymodel.c
quantize.c
quantize_pvt.c
xmm_quantize_sub.c
set_get.c
vbrquantize.c
reservoir.c
tables.c
takehiro.c
util.c
mpglib_interface.c
VbrTag.c
presets.c
version.c

--- LAME MP3 ENCODING LIBRARY UPTODATE ---

common.c
dct64_i386.c
decode_i386.c
layer1.c
layer2.c
layer3.c
tabinit.c
interface.c

--- HIP DECODING LIBRARY UPTODATE ---


--=* .\output\libmp3lame-static.lib ready *=--

main.c
get_audio.c
parse.c
timestatus.c
lametime.c
console.c
brhist.c

--- COMMON FRONTEND STUFF UPTODATE ---

lame_main.c
Microsoft (R) Windows (R) Resource Compiler Version 10.0.10011.16384
Copyright (C) Microsoft Corporation.  All rights reserved.


--=* .\output\lame.exe ready *=--


--=* lame.exe uptodate *=--

PS C:\Users\zjc20\source\lame-3.100>

可以看到成功编译了源代码为exe也就是可执行文件
在这个例子中,lame的源文件中的INSTALL文件中的说明很全。所以配置好环境之后就可以编译了。主要是学到了不少东西。
之前我一直是在Linux上操作的,Linux对源码的支持度比较好,我也查了原因后面我会放链接。而到了window系统之后就比较的头疼。
原因有
一是:我在window上使用的比较多的是解释型语言:python,而且语言比较单一所以只要配置好python环境就好。可是像实现比较大的项目的源码使用,如果单独使用python的就直接照着readme的使用方法干就好了。有融合的,只要环境配置的对也还是没多大的问题,因为一般都是只需要在Linux上干就行了,但是到了这种要输出为一个Windows可执行文件的我还没尝试过,之前搞C++和C时使用的还是devC++这种直接编写然后来个编译并运行就行了。
二是对window的系统并不了解。Windows系统比较复杂,对我这样的小白是这样的。所以在Linux中编写,编译,运行都比较简单。像make,cofigure,就比较简单。现在看看Linux与window的区别:

与Linux系列操作系统不同,Windows原生环境不提供类似gcc,Clang的C/C++语言源程序编译运行工具链。运行在Windows上的IDE(集成开发环境),比如CodeBlocks之类,一般都使用MinGW(Minimalist GNU for Windows)配置模拟Linux下的开发环境来进行Windows下的开发。
但是在Windows下,与开发环境以及code编辑器协同更好的还是MSVC(Microsoft Visual C/C++)编译器。对于灵活程度更高的code编辑器,我们可以将Microsoft的Visual C/C++编译器下载并集成到code中。

其三:我习惯性使用VScode,而VScode只是一个类似于记事本一样的东西,并没有什么实际功能,所以只能不断地配置。也就是说我更习惯在命令行去干活。“月才越爱玩”,像gcc,一些比较简单的编译还是会的,一旦到了makefile,或是,点sh文件就没有试过了,虽然对这些文件的理解是:他们就像脚本和命令行一样,是自动化的一种形式。但是实在是搞不明白,总感觉这种跟计算机底层的相关性很强。而且这个项目的config和makefile东西是真的多:要不是看INSTALL文件,真的不知道什么意思。


C:.
│   acinclude.m4
│   aclocal.m4
│   API
│   ChangeLog
│   compile
│   config.guess
│   config.h.in
│   config.log
│   config.rpath
│   config.sub
│   configMS.h
│   configure
│   configure.in
│   COPYING
│   DEFINES
│   depcomp
│   HACKING
│   INSTALL
│   install-sh
│   INSTALL.configure
│   lame.bat
│   lame.spec
│   lame.spec.in
│   LICENSE
│   ltmain.sh
│   Makefile.am
│   Makefile.am.global
│   Makefile.in
│   Makefile.MSVC
│   Makefile.unix
│   missing
│   README
│   README.WINGTK
│   STYLEGUIDE
│   testcase.mp3
│   testcase.wav
│   TODO
│   USAGE
│
├───.vs
│   │   slnx.sqlite
│   │   VSWorkspaceState.json
│   │
│   └───lame-3.100
│       ├───FileContentIndex
│       │   │   b4658905-267a-40dc-a6ab-7ec6f8b836c3.vsidx
│       │   │   read.lock
│       │   │
│       │   └───merges
│       └───v17
├───ACM
│   │   ACM.cpp
│   │   ACM.h
│   │   acm.rc
│   │   ACMStream.cpp
│   │   ACMStream.h
│   │   adebug.h
│   │   AEncodeProperties.cpp
│   │   AEncodeProperties.h
│   │   DecodeStream.cpp
│   │   DecodeStream.h
│   │   lame.ico
│   │   lameACM.def
│   │   LameACM.inf
│   │   lame_acm.xml
│   │   main.cpp
│   │   Makefile.am
│   │   Makefile.in
│   │   readme.txt
│   │   resource.h
│   │   TODO
│   │
│   ├───ADbg
│   │       ADbg.cpp
│   │       ADbg.h
│   │       Makefile.am
│   │       Makefile.in
│   │
│   ├───ddk
│   │       Makefile.am
│   │       Makefile.in
│   │       msacmdrv.h
│   │
│   └───tinyxml
│           changes.txt
│           dox
│           makedistlinux
│           makedistwin.bat
│           Makefile.am
│           Makefile.in
│           Makefile.tinyxml
│           readme.txt
│           tinyxml.cpp
│           tinyxml.h
│           tinyxmlerror.cpp
│           tinyxmlparser.cpp
│           xmltest.cpp
│
├───debian
│   │   .cvsignore
│   │   changelog
│   │   compat
│   │   control
│   │   copyright
│   │   lame.doc-base
│   │   lame.docs
│   │   lame.install
│   │   lame.manpages
│   │   libmp3lame-dev.install
│   │   libmp3lame0.install
│   │   Makefile.am
│   │   Makefile.in
│   │   rules
│   │   watch
│   │
│   ├───CVS
│   │       Entries
│   │       Repository
│   │       Root
│   │
│   └───source
│       │   format
│       │
│       └───CVS
│               Entries
│               Repository
│               Root
│
├───Dll
│       BladeMP3EncDLL.c
│       BladeMP3EncDLL.def
│       BladeMP3EncDLL.h
│       Example.cpp
│       LameDLLInterface.htm
│       Makefile.am
│       Makefile.in
│       Makefile.mingw32
│       MP3export.pas
│       README
│
├───doc
│   │   Makefile.am
│   │   Makefile.in
│   │
│   ├───html
│   │       about.html
│   │       abr.html
│   │       cbr.html
│   │       contact.html
│   │       contributors.html
│   │       detailed.html
│   │       history.html
│   │       index.html
│   │       introduction.html
│   │       links.html
│   │       list.html
│   │       Makefile.am
│   │       Makefile.in
│   │       ms_stereo.html
│   │       usage.html
│   │       vbr.html
│   │
│   └───man
│           lame.1
│           Makefile.am
│           Makefile.in
│
├───dshow
│       aboutprp.cpp
│       aboutprp.h
│       elogo.ico
│       Encoder.cpp
│       Encoder.h
│       iaudioprops.h
│       Makefile.am
│       Makefile.in
│       Mpegac.cpp
│       Mpegac.def
│       Mpegac.h
│       Property.rc
│       PropPage.cpp
│       PropPage.h
│       PropPage_adv.cpp
│       PropPage_adv.h
│       README
│       REG.CPP
│       REG.H
│       resource.h
│       UIDS.H
│
├───frontend
│       amiga_mpega.c
│       brhist.c
│       brhist.h
│       console.c
│       console.h
│       depcomp
│       get_audio.c
│       get_audio.h
│       gpkplotting.c
│       gpkplotting.h
│       gtkanal.c
│       gtkanal.h
│       lametime.c
│       lametime.h
│       lame_main.c
│       main.c
│       main.h
│       Makefile.am
│       Makefile.in
│       mp3rtp.c
│       mp3x.c
│       parse.c
│       parse.h
│       rtp.c
│       rtp.h
│       timestatus.c
│       timestatus.h
│
├───include
│       lame.def
│       lame.h
│       libmp3lame.sym
│       Makefile.am
│       Makefile.in
│
├───libmp3lame
│   │   bitstream.c
│   │   bitstream.h
│   │   depcomp
│   │   encoder.c
│   │   encoder.h
│   │   fft.c
│   │   fft.h
│   │   gain_analysis.c
│   │   gain_analysis.h
│   │   id3tag.c
│   │   id3tag.h
│   │   l3side.h
│   │   lame-analysis.h
│   │   lame.c
│   │   lame.rc
│   │   lameerror.h
│   │   lame_global_flags.h
│   │   logoe.ico
│   │   machine.h
│   │   Makefile.am
│   │   Makefile.in
│   │   mpglib_interface.c
│   │   newmdct.c
│   │   newmdct.h
│   │   presets.c
│   │   psymodel.c
│   │   psymodel.h
│   │   quantize.c
│   │   quantize.h
│   │   quantize_pvt.c
│   │   quantize_pvt.h
│   │   reservoir.c
│   │   reservoir.h
│   │   set_get.c
│   │   set_get.h
│   │   tables.c
│   │   tables.h
│   │   takehiro.c
│   │   util.c
│   │   util.h
│   │   vbrquantize.c
│   │   vbrquantize.h
│   │   VbrTag.c
│   │   VbrTag.h
│   │   version.c
│   │   version.h
│   │
│   ├───i386
│   │       choose_table.nas
│   │       cpu_feat.nas
│   │       fft.nas
│   │       fft3dn.nas
│   │       fftfpu.nas
│   │       fftsse.nas
│   │       ffttbl.nas
│   │       Makefile.am
│   │       Makefile.in
│   │       nasm.h
│   │       scalar.nas
│   │
│   └───vector
│           lame_intrin.h
│           Makefile.am
│           Makefile.in
│           xmm_quantize_sub.c
│
├───mac
│       .DS_Store
│       LAME.mcp
│       LAME_Carbon_Debug.pch
│       LAME_Carbon_Final.pch
│       LAME_Classic_Debug.pch
│       LAME_Classic_Final.pch
│       MacDLLMain.c
│       Makefile.am
│       Makefile.in
│       Precompile_Common.h
│
├───macosx
│   │   Info.plist
│   │   LAME_Prefix.pch
│   │   Makefile.am
│   │   Makefile.in
│   │
│   ├───English.lproj
│   │       InfoPlist.strings
│   │       Makefile.am
│   │       Makefile.in
│   │
│   └───LAME.xcodeproj
│           Makefile.am
│           Makefile.in
│           project.pbxproj
│
├───misc
│       abx.c
│       ath.c
│       auenc
│       depcomp
│       Lame.vbs
│       lame4dos.bat
│       lameGUI.html
│       lameid3.pl
│       Makefile.am
│       Makefile.in
│       mk_mp3.sh
│       mlame
│       mlame_corr.c
│       mugeco.sh
│       scalartest.c
│
├───mpglib
│       AUTHORS
│       common.c
│       common.h
│       dct64_i386.c
│       dct64_i386.h
│       decode_i386.c
│       decode_i386.h
│       depcomp
│       huffman.h
│       interface.c
│       interface.h
│       l2tables.h
│       layer1.c
│       layer1.h
│       layer2.c
│       layer2.h
│       layer3.c
│       layer3.h
│       Makefile.am
│       Makefile.in
│       mpg123.h
│       mpglib.h
│       README
│       tabinit.c
│       tabinit.h
│
└───vc_solution
        arch_nasm.vsprops
        arch_sse2.vsprops
        arch_x87.vsprops
        Makefile.am
        Makefile.in
        vc9_lame.sln
        vc9_lame_acm.vcproj
        vc9_lame_acm_adbg.vcproj
        vc9_lame_acm_tinyxml.vcproj
        vc9_lame_clients.sln
        vc9_lame_config.vsprops
        vc9_lame_dll.vcproj
        vc9_lame_dll_example.vcproj
        vc9_lame_dshow.vcproj
        vc9_lame_lame.vcproj
        vc9_lame_mp3rtp.vcproj
        vc9_lame_mp3x.vcproj
        vc9_lame_test.vcproj
        vc9_libmp3lame.vcproj
        vc9_libmp3lame_dll.vcproj
        vc9_mpglib.vcproj
        vc9_nasm.rules

=======================================================================
Building the software on *NIX platforms using configure:
=======================================================================
Run the following commands:

% ./configure
% make
% make install

For a complete list of options, try "./configure --help"
Some of the more usefull options:
=======================================================================
Building the software on Windows with MSVC:
(or MSVC + 3rd party C compiler such as ICL)
=======================================================================
There are MSVC project files, and a Makefile.MSVC included with the 
project.  For production use, be sure to compile a "Release" target, 
with the "maximum speed" compile option, and #define NDEBUG.   

It is possible to compile the GTK frame analyzer under windows, see
README.WINGTK

Various build options can be set in configMS.h

Note: project files for building lame.exe seem to be broken or not
quite compatable with MSVC6.  The most reliable way to build lame and
lame_enc.dll is to run the .bat script (comes with MSVC6) which sets
up your VC environment to work from the command line, and then:

copy configMS.h config.h 
nmake -f Makefile.MSVC  comp=msvc  asm=no

Project files for the dll, ACM codec and directshow filter 
seem to be in better sahpe.  

起因:foobar2000在格式转换中需要lame.exe。然而我只能找到源代码。人家是这么说的:

LAME is an educational tool to be used for learning about MP3 encoding. 

The goal of the LAME project is to improve the psycho acoustics, quality and speed of MP3 encoding. 

Note: we provide source code only!

Features
Source code only !!!

没办法了就这样吧。

想法:一:在Linux上试试编译可执行文件exe

linux上对环境的要求好像没有这么绕人。

这种办法叫做交叉编译, 要用到交叉编译器

方法没试

想法二:使用项目管理工具(也可以是IDE)来编译运行。

类比Linux原理

在 Angband 目录中,首先,运行随源码一起提供的配置脚本

$ ./configure

这一步将扫描你的系统,找到 Angband 正确构建所需的依赖性。有些依赖是非常基本的,没有它们你的电脑就无法运行,而有些则是专门的。在这一过程结束时,该脚本会给你一份关于它所发现的东西的报告。

一旦一切配置完毕,运行make命令:
$ make
这通常需要一段时间,但它提供了很多视觉反馈,所以你会知道代码正在被编译。

最后一步是安装你刚刚编译的代码。安装代码并没有什么神奇之处。所做的就是复制很多文件到非常具体的目录中。无论你是从源代码编译还是运行花哨的图形安装向导,都是如此。由于这些代码会被复制到系统级目录,你必须有 root(管理)权限,这是由 sudo命令授予的。
$ sudo make install
1
也就是说:原理就是这么些。开始看看有什么不同。
还好这个说明文档很清楚:
如何获取MSVC:
 一般来说,获取MSVC要通过Microsoft Visual Studio来实现。对于一般的应用场景来说,我们不需要下载完整的IDE而是只需要下载单个组件下的MSVC C++ 生成工具,以及Windows 10 SDK即可。(MSVC C++生成工具包含了全部编译链接工具链以及大部分函数库与头文件;Windows 10 SDK只是提供其它的一些必要库文件与头文件
developer powershell for vs 2022
要按照INSTALL来:Building the software on *NIX platforms using configure
接着。运行即可。

想法三:使用Cygwin。(这个有好多类似的。就是模仿Linux不在赘述)

想法四:使用wsl,与Linux异曲同工。依旧需要交叉编译。

在INSTALL后面还有许多说明。Building the software on Windows with free compilers.比较类似。就不说了。

总结就是严格按照说明文档。理解Linux与Windows的不同。而且知道编译的共通之处。

在写的过程中实验了很多Markdown的格式。也算是有所收获。

我还想知道例如python代码编译为可执行文件。这个好像要使用pyinstaller,有篇文章有说明。

就这样吧。累了。

one more thing

没有代码的纵向进度条是真的烦。厌倦了。


  1. https://linux.cn/article-14033-1.html#:~:text=%E5%85%B7%E4%BD%93%E6%9D%A5%E8%AF%B4%EF%BC%8C%E4%BD%A0%E9%9C%80%E8%A6%81%E4%B8%80%E4%B8%AA%E7%BC%96%E8%AF%91%E5%99%A8%E3%80%82%20%E7%BC%96%E8%AF%91%E5%99%A8%EF%BC%88%E6%AF%94%E5%A6%82%20GCC%20%E6%88%96%20LLVM%EF%BC%89%E5%8F%AF%E4%BB%A5%E5%B0%86%E5%83%8F%E8%BF%99%E6%A0%B7%E7%9A%84%E6%BA%90%E4%BB%A3%E7%A0%81%EF%BC%9A%20%23include%20%3Ciostream%3E%20using,%22hello%20world%22%3B%20%7D%20%E5%8F%98%E6%88%90%20%E6%9C%BA%E5%99%A8%E8%AF%AD%E8%A8%80%20%EF%BC%8C%E5%8D%B3%20CPU%20%E7%94%A8%E6%9D%A5%E5%A4%84%E7%90%86%E4%BF%A1%E6%81%AF%E7%9A%84%E6%8C%87%E4%BB%A4%E3%80%82

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/apple_53371070/article/details/128774007

智能推荐

A problem occurred configuring project ':app'. > Failed to notify project evaluation listener. >-程序员宅基地

文章浏览阅读2.7w次,点赞2次,收藏3次。出现以下错误的解决方法:* What went wrong:A problem occurred configuring project ':app'.> Failed to notify project evaluation listener. > Could not initialize class com.android.sdklib.repository.AndroidSd..._a problem occurred configuring project ':app'. > failed to notify project ev

服务器上什么叫节点位置,服务器中内存和节点什么意思-程序员宅基地

文章浏览阅读1.4k次。服务器中内存和节点什么意思 内容精选换一换香港节点和大陆节点的区别如下:香港节点购买域名后无需备案,可以直接在后台绑定域名并使用。大陆节点购买域名后需要先完成备案,才可以在后台绑定域名。香港节点支持绑定多个一级或者子域名,大陆节点只能绑定一个一级域名和多个子域名。香港节点不支持对接小程序和公众号。云速建站是自适应建站,不是响应式建站。自适应是根据访问设备不同自动匹配不同的网站,即请检查您的加速域名..._服务器节点是什么意思

每天计划完成打勾的app 做完一个打一个勾那种便签_有没有app 计划多少个 实际完成多少个-程序员宅基地

文章浏览阅读1.2k次。对于忙碌的职场人士来说,每天都有很多事情要处理。为了不把重要的事情漏掉,需要把待办的事项列下来,做完一个打勾一个,这样一看待办列表,自己做了多少事、还有多少事情没做就可以一目了然。现在有做完一个打一个勾的那种便签,可以帮助用户很好地记录待办事项,这样的便签就是敬业签。一起来看看,敬业签怎么新建待办并打勾完成吧!以手机敬业签为例:1:打开并登录敬业签后,点击底部的“待办”,新增一个待办分类。2:在分类管理页面点右上角+,启动新增待办分类菜单,分类类型选择“待办”,然后填写分类名称并点右下角新增,就可_有没有app 计划多少个 实际完成多少个

ONVIF Server 鉴权实现代码(服务端)_digest&ws-username token-程序员宅基地

文章浏览阅读2.6k次。ONVIF鉴权实现代码生成gSOAP框架代码,这个网上有很多教程,需要加入很多文件,并且需要openssl库。加入需要鉴权的文件和openssl库以后,只需要加每个接口中加入鉴权操作的代码,调用的时候就能实现鉴权。ONVIF的鉴权分两种: HTTP Digest 和 WS-Username Token在ONVIF Device Test Tool上可以对两种鉴权分别进行测试。authenticate.h#ifndef __AUTHENTICATE_H__#define __AUTHENTICAT_digest&ws-username token

优化APK体积_android apk 大小优化-程序员宅基地

文章浏览阅读1.2k次。该篇文章主要来介绍如何减少APK体积,以帮助用户更快地下载App,并加速安装/更新过程。_android apk 大小优化

通用存储过程分页(top max模式)版本(性能相对之前的not in版本极大提高) _top 搭配not in 性能-程序员宅基地

文章浏览阅读1.3k次。 --/*-----存储过程 分页处理 孙伟 2005-03-28创建 -------*/--/*----- 对数据进行了2分处理使查询前半部分数据与查询后半部分数据性能相同 -------*/--/*-----存储过程 分页处理 孙伟 2005-04-21修改 添加Distinct查询功能-------*/--/*-----存储过程 分页处理 孙伟 2005-05-18修改 多字段排序规则问题-_top 搭配not in 性能

随便推点

树莓派(Raspberry Pi 4)开启和连接蓝牙_树莓派连接蓝牙耳机并使用麦克风-程序员宅基地

文章浏览阅读1.8w次,点赞4次,收藏43次。参考连接: link.1、查看树莓派蓝牙开启状态_树莓派连接蓝牙耳机并使用麦克风

Python3输入输出与字符串格式化_%s.%d' %()-程序员宅基地

文章浏览阅读3.3k次,点赞3次,收藏12次。介绍了输入(input)、输出(print),及字符串格式化(F-string、format与%)方式_%s.%d' %()

EL表达式比较字符串或是数字格式的数值是否相等,为true,却不执行为true时的代码_el 表达式 判断字符串和数字相等-程序员宅基地

文章浏览阅读9.3k次。问题:EL表达式比较字符串或是数字格式的数值是否相等,为true,却不执行为true时的代码。示例:true原因:有可能是test="${ 1 == 1}(这里多个空格)",即大括号与双引号之间多了空格,这个时候,就不会打印true。去掉多余的空格就可以了_el 表达式 判断字符串和数字相等

GCC-3.4.6源代码学习笔记(26续1)_-feliminate-unused-debug-types-程序员宅基地

文章浏览阅读2k次。common_handle_option (continue) 909 case OPT_fcall_used_:910 fix_register (arg, 0, 1);911 break;912 913 case OPT_fcall_saved_:914 fix_register (arg, 0, 0)_-feliminate-unused-debug-types

python语言程序设计实践教程陈东上海交通大学答案_《软件开发训练营:ASP.NET开发一站式学习难点》杨云著【摘要 书评 在线阅读】-苏宁易购图书...-程序员宅基地

文章浏览阅读2.7k次。商品参数作者:杨云著出版社:清华大学出版社出版时间:2013-8-1版次:1印次:1印刷时间:2013-8-1页数:434开本:16开装帧:平装ISBN:9787302318286版权提供:清华大学出版社编辑推荐《软件开发训练营·ASP.NET开发一站式学习:难点·案例·练习》特色:1.《软件开发训练营·ASP.NET开发一站式学习:难点·案例·练习》所讲内容既避开艰涩难懂的理论知识,又覆盖了编程..._python语言程序设计实践教程陈东课后习题答案解析

解决:Qt项目构建成功,但是运行异常退出。_qt安装后构建可以,运行就一直提示程序异常-程序员宅基地

文章浏览阅读2k次。构建:从debug换成release:就可以正常运行了_qt安装后构建可以,运行就一直提示程序异常