Visual Studio 2017 批量去掉代码优化的方法


  • 网站研运

    由于我们在二次开发的过程中,需要采用调试来测试开发的效果,而使用cmake生成的Visual Studio项目,代码都是O2优化的,不太符合我们的需求,而我们必须每次都要载入Visual Studio 2017手动修改代码优化到禁用,这的确有一些麻烦,于是我们需要找一个更加便利的方法达到效果。我在稍微研究了一下之后得到结论:其实很好解决。

    准备环境

    Windows 10
    Visual Studio 2017
    Notepad++

    随便打开一个vcxproj文件,然后按下快捷键:Ctrl + F,转到文件查找一栏。按照下面的要求填写:

    文件类型 *.vcxproj
    查找目标 <Optimization>MaxSpeed</Optimization>
    替换为 <Optimization>Disabled</Optimization>

    然后点击“在文件中替换”,等待一会儿,就可以看到优化全部去掉了。这样就可以顺利地单步调试而不会出现断点下不了或者是其它问题了。
    替换代码优化



  • 脚本玩家路过一下😁
    我写了一段Powershell脚本,可以一键打开/关闭调试信息和代码优化。
    原理就是解析.sln文件(xml格式),找到关联的所有.vcproj文件(也是xml格式),并把其中的字段修改掉。

    看脚本

    # filename: DebugInfoSwitch.ps1
    Add-Type -AssemblyName System.Xml.Linq
    
    # 获取绝对路径
    function GetAbsolutePath {
        [OutputType([string])]
        param([string]$filePath)
    
        $aPath = Resolve-Path $filePath
    
        return Split-Path $aPath
    }
    # 解析sln文件,提取出project列表
    function ParseSolution {
        [OutputType([string[]])]
        param([string]$solutionFile)
    
        $parttern = [regex]"^Project*"
        [string[]] $projs = @()
        Get-Content $solutionFile | Where-Object {$_ -match $parttern} | ForEach-Object {
            $items = $_.ToString().Split(',')
            
            if ($items[1].EndsWith("vcxproj`"")) {
                $projs += $items[1]
            }
        }
        return $projs
    }
    #Write-Host($debugGroup | Format-Table | Out-String )
    function UpdateDebugInfo {
        param([System.Xml.Linq.XNamespace]$xNamespace,[System.Xml.Linq.XElement] $group, [bool]$isOpen)
        [System.Xml.Linq.XElement]$xClCompile =  $group.Element($xNamespace + "ClCompile")
        [System.Xml.Linq.XElement]$xLink =  $group.Element($xNamespace + "Link")
        [System.Xml.Linq.XElement]$format = $xClCompile.Element($xNamespace + "DebugInformationFormat")
        [System.Xml.Linq.XElement]$optimization = $xClCompile.Element($xNamespace + "Optimization")
        [System.Xml.Linq.XElement]$generate = $xLink.Element($xNamespace + "GenerateDebugInformation")
        if ($null -eq $format) {
            $format = [System.Xml.Linq.XElement]::new($xNamespace + "DebugInformationFormat")
            $xClCompile.Add($format)
        }
        if ($null -eq $optimization) {
            $optimization = [System.Xml.Linq.XElement]::new($xNamespace + "Optimization")
            $xClCompile.Add($optimization)
        }
        if ($null -eq $generate) {
            $generate = [System.Xml.Linq.XElement]::new($xNamespace + "GenerateDebugInformation")
            $xLink.Add($generate)
        }
        if ($isOpen) {
            $format.SetValue("ProgramDatabase");
            $optimization.SetValue("Disabled");
            $generate.SetValue("true");
        } else {
            $format.SetValue("None");
            $optimization.SetValue("MaxSpeed");
            $generate.SetValue("false");
        }
    }
    function SwitchDebugInfo {
        param([string]$projPath, [bool]$open, [bool]$isRelease)
        if (Test-Path($projPath)) {
            [System.Xml.Linq.XDocument]$xDoc = [System.Xml.Linq.XDocument]::Load($projPath)
            [System.Xml.Linq.XNamespace]$xNamespace = $xDoc.Root.GetDefaultNamespace();
            [System.Xml.Linq.XElement]$group = $null
            $groups = $xDoc.Root.Elements($xNamespace + "ItemDefinitionGroup")
            foreach ($i in $groups) {
                if ($isRelease) {
                    if ($i.Attribute("Condition").Value -match "^*Release*") 
                    {
                        $group = $i;
                        break;
                    }
                } else {
                    if ($i.Attribute("Condition").Value -match "^*Debug*") 
                    {
                        $group = $i;
                        break;
                    }
                }
            }
            UpdateDebugInfo $xNamespace $group $open
            $xDoc.Save($projPath)
         }
    }
    #脚本入口函数
    function Main {
        param([string]$sln, [bool]$open, [bool]$isRelease)
        Write-Host("sln file ", $sln)
        $slnPath= GetAbsolutePath $sln
        $projList = ParseSolution $sln 
        $t = $projList.Split(' ') | ForEach-Object {
            $s = $_.ToString()
            if ($s) {
                $projPath=-Join($slnPath, '\', ($s.SubString(1, $s.Length - 2) ))
                SwitchDebugInfo $projPath $open $isRelease
            }
        }
    }
    function Usage {
        Write-Host ("Usage: DebugInfoSwitch.ps1 slnFilePath mode[D/d for Debug, R/r for Release] open[Y/y for open, N/n for close]")
        Write-Host ("Example for open Release mode debugInfo: DebugInfoSwitch.ps1 xxx.sln R y")
        Write-Host ("Example for close Debug mode debugInfo: DebugInfoSwitch.ps1 xxx.sln d N")
    }
    #检查参数
    [string]$sln = ""
    [bool]$open = $true
    [bool]$isRelease = $false
    if ( $args.Count -ne 3) {
        Usage
        return 
    }
    $sln = $args[0]
    if ($args[1] -eq "D" -or $args[1] -eq "d") {
        $isRelease = $false
    } elseif ($args[1] -eq "R" -or $args[1] -eq "r") {
        $isRelease = $true
    } else {
        Usage
        return
    }
    if ($args[2] -eq "Y" -or $args[2] -eq "y") {
        $open = $true
    } elseif ($args[2] -eq "N" -or $args[2] -eq "n") {
        $open = $false
    } else {
        Usage
        return
    }
    #调用主函数
    Main $sln $open $isRelease
    

    用的时候,再写个bat脚本,调用这个ps1并传参数就行了。
    比如打开Release模式的调试信息、同时关掉优化开关

    @echo off
    powershell.exe -NoProfile -ExecutionPolicy Bypass -File DebugInfoSwitch.ps1 ./you/path/to.sln R N
    

    关闭调试信息、打开优化开关,则是传相反的参数

    @echo off
    powershell.exe -NoProfile -ExecutionPolicy Bypass -File DebugInfoSwitch.ps1 ./you/path/to.sln R Y
    


  • @wentaojia2014
    代码中的 {1} 是自动生成的,注意删掉


  • 网站研运

    看了你的脚本,看来PowerShell是一种shell的方言,支持function和自定义的符号。和bash还不一样。
    我以前也写过Apple Script,看来大家都在shell语言上加上自己的特性啊。
    顺便了解到你们主要用Visual Studio开发Qt应用的。😁 😁


Log in to reply
 

走马观花

最近的回复

  • 这个错误没多大影响,qt模块可以在QT setting里进行勾选

    read more
  • 如果对操作不是很熟悉或者是操作不便的话,也可以在Windows的命令行执行NDK的安装。参数是一样的:
    Windows命令行安装NDK

    read more
  • 忘记补充图片了。这里需要点击更新安装才行。😆
    点击更新安装

    read more
  • 问:
    如何在Qt Creator安装NDK呢?
    除了那个🔽 按钮外,还有别的办法吗?
    答:
    Qt Creaator 4.11中更加整合了Android SDK Manager。其实大家都可以不运行默认的Android SDK Manager,直接在Qt Creator中选项->设备->Android,就可以进行操作了。

    通过````高级选项……,启动一些Android SDK Manager,只需要带上参数ndk-bundle```。原来没有NDK的你,也可以通过Android SDK Manager安装了。很简单吧。
    Android SDK Manager安装NDK

    read more

关注我们

微博
QQ群