CodeBlocks Portable mit MinGW 32 und 64 Bit unter Windows
Inhaltsverzeichnis
1. Vorwort
Hallo Community.Neben dem VC++ bin ich mit Code::Blocks als IDE für C und C++ unter Windows einigermaßen glücklich. Während man den VC++ wohl nicht dazu überreden kann auch portable zu funktionieren, geht das bei Code::Blocks mit wenigen Tricks. Es gibt auch bereits Portable Versionen, die mich aber nicht überzeugt haben. Aus diesem Grund hatte ich damit begonnen eine eigene Umsetzung zu entwickeln. Ein VBScript schien mir anfangs der Weg des geringsten Widerstands, da leicht editierbar und mit dem benötigten XML Support.
Mehr als 10 Jahre nachdem ich diese Anleitung erstmalig veröffentlicht habe ( (obsolet) CodeBlocks Portable mit MinGW 32 und 64 Bit unter Windows ), ist VBScript von Microsoft als veraltet markiert. Heißt, der Launcher hat nun eine grafische Benutzeroberfläche, basierend auf PowerShell und WPF. Es gibt mittlerweile auch MinGW basierte Compilerbuilds mit einem LLVM/CLang Toolset, um weitere Prozessorarchitekturen zu unterstützen, die ich in dieser Anleitung zitiere.
Vielleicht ist diese Lösung auch für euch von Interesse.
Grüße
Steffen
2. Voraussetzungen
- Windows 10 Betriebssystem oder neuer (getestet unter Win10 x64 und Win11 x64)
- Windows PowerShell 5.1 oder PowerShell Core
- > 1,1 GB Speicherplatz
3. Vorbereitung
Natürlich benötigt man eine entsprechende Verzeichnisstruktur, damit das Ganze auch funktioniert. Weil Compiler über die Kommandozeile angesteuert werden, ist es sicherer wenn keines der Verzeichnisse und Unterverzeichnisse Leerzeichen oder Sonderzeichen, wie & oder % enthält.- Zunächst also ein neues Verzeichnis anlegen, sinnvollerweise "CodeBlocksPortable" benennen. (Dort erstellen, wo du uneingeschränkte Schreibrechte auf die Verzeichnisstruktur hast!)
- In dieses Verzeichnis ein Unterverzeichnis "CodeBlocks", das die IDE beinhalten soll,
- ein Unterverzeichnis "Projects", das später die Projekte beinhaltet,
- sowie eine weiteres Unterverzeichnis "Additional_Include". Dort können selbst erstellte Header Dateien abgelegt werden, die immer wieder verwendet werden, oder auch bspw. die gern verwendeten "Boost" Header.
(Anmerkung: Wird im "Projects" Verzeichnis ein Unterverzeichnis "_archive_" erstellt, in das abgeschlossen Projekte verschoben werden können, so bleiben diese Projekte für die Anzeige in "Recent projects" des Code::Blocks Startfensters ausgeschlossen.)
Die Struktur sollte nun also so aussehen:
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
└─ Projects
4. Installationen
4.1. Code::Blocks (IDE)
Die codeblocks-NN.MM-nosetup.zip hier (www.codeblocks.org/downloads/binaries) downloaden. NN.MM steht dabei für die aktuelle Version. (Aktuell codeblocks-20.03-nosetup.zip)WICHTIG: Nicht das mingw enthaltende Archiv herunterladen! Dort käme eine GCC Version mit, die unvollständige Windows Header beinhaltet.
Den Inhalt des ZIP Archivs in das "CodeBlocks" Unterverzeichnis entpacken.
Im CodeBlocks Unterverzeichnis sollten sich nun unter anderem das "share" Verzeichnis und die "codeblocks.exe" finden:
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
│ ├─ share
│ └─ (codeblocks.exe)
│
└─ Projects
4.2. Compiler
Nun, da die IDE vorhanden ist, benötigst du noch einen Compiler. Genauer gesagt sind es mindestens zwei Compiler, um das Feature nutzen zu können sowohl 32-Bit als auch 64-Bit-Applikationen erstellen zu können.Du findest sie hier (github.com/mstorsjo/llvm-mingw/releases).
Die unter Windows verwendbaren Compiler sind ZIP Archive mit Namen, die dem folgenden Muster entsprechen:
"llvm-mingw-<YYYYMMDD>-<C-Laufzeitbibliothek>-<Zielprozessor>.zip"
- <YYYYMMDD> steht für Jahr, Monat und Tag des Releasedatums.
- <C-Laufzeitbibliothek> ist der Name der DLL, die die Implementierung der C-Funktionen enthält. Dabei ist "ucrt" erst ab Win10 vorinstalliert, während zu "msvcrt" gelinkte Apps auch zu älteren Windowsversionen kompatibel sind.
- <Zielprozessor> bezeichnet die Prozessorfamile für die deine Apps kompiliert werden. "i686" steht für 32-Bit Intel Prozessoren, "armv7" für 32-Bit ARM Prozessoren, "x86_64" für 64-Bit AMD oder Intel Prozessoren und "aarch64" für 64-Bit ARM64 Prozessoren.
Wer unsicher ist, welche Compiler für seinen Rechner geeignet sind - Die Wahrscheinlichkeit ist hoch, dass man mit folgenden beiden die richtige Wahl trifft:
"llvm-mingw-<YYYYMMDD>-msvcrt-i686.zip" für die Kompilierung von 32-Bit Apps
"llvm-mingw-<YYYYMMDD>-msvcrt-x86_64.zip" für die Kompilierung von 64-Bit Apps
Wähle die jeweils aktuellste Version. In den Archiven enthalten ist jeweils ein Verzeichnis mit demselben Name wie die ZIP Datei.
Die *.zip Dateien in "CodeBlocksPortable\CodeBlocks" entpacken. Die neue Verzeichnisstruktur könnte nun bspw. so aussehen:
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
│ ├─ llvm-mingw-20231031-msvcrt-i686
│ ├─ llvm-mingw-20231031-msvcrt-x86_64
│ ├─ share
│ └─ (codeblocks.exe)
│
└─ Projects
4.3. Deutsches Menü gefällig?
Wer mit der englischen Menüführung in Code::Blocks glücklich ist, sollte diesen Punkt überspringen. Wer lieber ein weitgehend deutsches Menü bevorzugt, benötigt noch eine zusätzliche Datei "codeblocks.mo". Diese muss in folgendem Pfad liegen:"CodeBlocksPortable\CodeBlocks\share\CodeBlocks\locale\de_DE"
Nicht existierende Unterverzeichnisse müssen erstellt werden.
Eine Anleitung und die Datei findest du hier (www.opensource-dvd.de/programme/codeblocks.htm).
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
│ ├─ llvm-mingw-20231031-msvcrt-i686
│ ├─ llvm-mingw-20231031-msvcrt-x86_64
│ ├─ share
│ │ └─ CodeBlocks
│ │ └─ locale
│ │ └─ de_DE
│ │ └─ (codeblocks.mo)
│ │
│ └─ (codeblocks.exe)
│
└─ Projects
5. CB-Portable-Launcher.ps1
5.1. Das Script
Mit dem folgenden PowerShell Script wird "codeblocks.exe" mit den entsprechenden Voreinstellungen gestartet. Somit wird "Code::Blocks" zu "Code::Blocks Portable"Das Script unter dem Name "CB-Portable-Launcher.ps1" im "CodeBlocksPortable" Verzeichnis speichern.
Add-Type -AssemblyName 'PresentationFramework', 'System.Drawing'
Add-Type -Namespace 'P' -Name 'Invoke' -MemberDefinition @'
[StructLayout(LayoutKind.Sequential)]
struct PropertyKey {
Guid fmtId;
int pId;
internal PropertyKey(int propId) {
fmtId = new Guid("9F4C2855-9F79-4B39-A8D0-E1D42DE1D5F3"); // format ID of all System.AppUserModel properties
pId = propId;
}
}
[StructLayout(LayoutKind.Explicit)]
struct PropVariant {
[FieldOffset(0)] VarEnum vt;
[FieldOffset(8), MarshalAs(UnmanagedType.LPWStr)] string val;
internal PropVariant(VarEnum varType) {
vt = varType;
val = "Public.CB_Portable_Launcher_ps1"; // bodgy: if vt is VT_BOOL, the string pointer is intended to be interpreted as boolean TRUE
}
}
[ComImport, Guid("886D8EEB-8CF2-4446-8D02-CDBA1DBDCF99"), InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
interface IPropertyStore {
int GetCount(ref int cProps);
int GetAt(int iProp, ref PropertyKey pkey);
int GetValue(ref PropertyKey key, PropVariant pv);
int SetValue(ref PropertyKey key, PropVariant pv);
int Commit();
}
[DllImport("shell32.dll")]
static extern int SHGetPropertyStoreForWindow(IntPtr wnd, ref Guid riid, out IPropertyStore ppv);
static void SetPropVal(IPropertyStore propStore, int propId, VarEnum varType) {
var propKey = new PropertyKey(propId);
propStore.SetValue(ref propKey, new PropVariant(varType));
}
public static void UpdateAppUserModel(IntPtr wnd) {
var iid = typeof(IPropertyStore).GUID;
IPropertyStore propStore;
SHGetPropertyStoreForWindow(wnd, ref iid, out propStore);
SetPropVal(propStore, 9, VarEnum.VT_BOOL); // .PreventPinning --> TRUE
SetPropVal(propStore, 5, VarEnum.VT_LPWSTR); // .ID --> custom string
}
[DllImport("dwmapi.dll")]
public static extern int DwmSetWindowAttribute(IntPtr wnd, int attrId, ref int attr, int attrSize);
[DllImport("kernel32.dll")]
public static extern IntPtr GetConsoleWindow();
[DllImport("kernel32.dll")]
public static extern void GetNativeSystemInfo(Int16[] sysInf);
[DllImport("shcore.dll")]
public static extern int SetProcessDpiAwareness(int value);
[DllImport("user32.dll")]
public static extern int ShowWindowAsync(IntPtr wnd, int state);
'@
#region fallback strings
$script:sId_0 = 'CodeBlocks and compiler directory'
$script:sId_1 = 'Projects directory'
$script:sId_2 = 'Directory for additional header files'
$script:sId_3 = 'Compiler'
$script:sId_4 = 'Start'
$script:sId_5 = 'Cancel'
$script:sId_6 = 'Please select the Code::Blocks directory.'
$script:sId_7 = 'Please select the Projects directory.'
$script:sId_8 = 'Please select the Additional_Include directory.'
$script:sId_9 = '"Code::Blocks" has already been started in another process.
Close the "Code::Blocks" window and try again.'
$script:sId_10 = 'Error! Select the "CodeBlocks and compiler directory".'
$script:sId_11 = 'Error! Select the "Projects directory".'
$script:sId_12 = 'Error! Select the "Directory for additional header files".'
$script:sId_13 = 'The file "codeblocks.exe" was not found.
Check your selection in the "CodeBlocks and compiler directory" box.'
$script:sId_14 = 'Error! No compiler found. Visit'
$script:sId_15 = 'Ready. - There is a new compiler version. Visit'
$script:sId_16 = 'Ready. - If necessary, select the compiler for the target platform.'
#endregion fallback strings
#region predefined locations
$script:scriptDir = Split-Path $MyInvocation.MyCommand.Path
$script:prtblConf = Join-Path $script:scriptDir 'CB-Portable-Config.xml'
$script:i18nSpec = Join-Path $script:scriptDir 'CB-Portable-I18n.xml'
$script:urlLatest = 'https://github.com/mstorsjo/llvm-mingw/releases/latest'
#endregion predefined locations
#region error flags
& {
$flg = 1
'errCbDir', 'errProjDir', 'errAInclDir', 'errCbExe', 'errComp' | ForEach-Object { Set-Variable $_ $flg -Scope 'Script'; $flg *= 2 }
$script:errFlags = $flg - 1 # initially all defined flags are set and later conditionally cleared bit by bit to enable the 'Start' button
}
function Set-ErrFlag([int]$flg) { $script:errFlags = $script:errFlags -bOr $flg }
function Clear-ErrFlag([int]$flg) { $script:errFlags = $script:errFlags -bAnd (-bNot $flg) }
function Test-ErrFlag([int]$flg) { ($script:errFlags -bAnd $flg) -ne 0 }
#endregion error flags
function New-PrtblConf {
[xml]$script:xmlConf = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><CB_Portable_Launcher_Config version="2"><relative_paths><CBDir><![CDATA[|]]></CBDir><ProjDir><![CDATA[|]]></ProjDir><AdditionalIncludeDir><![CDATA[|]]></AdditionalIncludeDir></relative_paths></CB_Portable_Launcher_Config>'
$script:xmlConf.Save($script:prtblConf)
}
function New-I18nFile {
([xml]@"
<?xml version="1.0" encoding="UTF-8" standalone="yes"?><lang><!--
To add a new translation, use either the long or short form of the language
code as child-node name of the 'lang' root node. Each of the forms must be
based on a 'CurrentUICulture.Name' property of the .NET class
'System.Globalization.CultureInfo'.
- The long form consists of the combination of the 2 letters for the
language, an underscore, and the country/region code.
NOTE: The hyphen of the 'CurrentUICulture.Name' property is replaced with
an underscore to get a valid node name.
Example: 'zh_Hans' or 'zh_Hant'
- The short form is only the 2 letters for the language. Prefer this form if
there are no differences in translation for countries or regions that use
the same language.
Example: 'de' (instead of 'de_AT', 'de_DE' etc.)
Search order:
- The long form is found.
- Else, the short form is found.
- Else, a long form with the same language but different country/region code
is found.
- Else, fall back to English.
Make sure
- to use CDATA elemets for translated strings,
- to save the file UTF-8 encoded.
--><en><s id="0"><![CDATA[${script:sId_0}]]></s><s id="1"><![CDATA[${script:sId_1}]]></s><s id="2"><![CDATA[${script:sId_2}]]></s><s id="3"><![CDATA[${script:sId_3}]]></s><s id="4"><![CDATA[${script:sId_4}]]></s><s id="5"><![CDATA[${script:sId_5}]]></s>
<s id="6"><![CDATA[${script:sId_6}]]></s><s id="7"><![CDATA[${script:sId_7}]]></s><s id="8"><![CDATA[${script:sId_8}]]></s><s id="9"><![CDATA[${script:sId_9}]]></s><s id="10"><![CDATA[${script:sId_10}]]></s><s id="11"><![CDATA[${script:sId_11}]]></s>
<s id="12"><![CDATA[${script:sId_12}]]></s><s id="13"><![CDATA[${script:sId_13}]]></s><s id="14"><![CDATA[${script:sId_14}]]></s><s id="15"><![CDATA[${script:sId_15}]]></s><s id="16"><![CDATA[${script:sId_16}]]></s></en></lang>
"@).Save($script:i18nSpec)
}
function New-ConfFile {
param(
[Parameter(Mandatory = $True)][string]$confFile
)
PROCESS {
([xml]@'
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?><CodeBlocksConfig version="1"><app><environment><CHECK_ASSOCIATIONS bool="0" /></environment><SHOW_TIPS bool="0" /><RECENT_PROJECTS><astr /></RECENT_PROJECTS>
<locale><ENABLE bool="1" /></locale></app><project_manager><DEFAULT_PATH><str /></DEFAULT_PATH></project_manager><compiler><build_progress /><SETTINGS_VERSION><str><![CDATA[0.0.3]]></str></SETTINGS_VERSION>
<sets><gcc><NAME><str><![CDATA[GNU GCC Compiler]]></str></NAME><COMPILER_OPTIONS><str><![CDATA[-Wall;-std=c++20;-std=c17;-s;-ffunction-sections;-fdata-sections;]]></str></COMPILER_OPTIONS>
<LINKER_OPTIONS><str><![CDATA[-O3;-static-libstdc++;-static-libgcc;-Wl,-Bstatic -lstdc++ -lpthread;-Wl,--gc-sections;]]></str></LINKER_OPTIONS><MASTER_PATH><str /></MASTER_PATH><C_COMPILER><str><![CDATA[gcc.exe]]></str></C_COMPILER>
<CPP_COMPILER><str><![CDATA[g++.exe]]></str></CPP_COMPILER><LINKER><str><![CDATA[g++.exe]]></str></LINKER><MAKE><str><![CDATA[make.exe]]></str></MAKE></gcc></sets><DEFAULT_COMPILER><str><![CDATA[gcc]]></str></DEFAULT_COMPILER></compiler>
<debugger_common><sets><gdb_debugger><conf1><NAME><str><![CDATA[Default]]></str></NAME><values><EXECUTABLE_PATH><str /></EXECUTABLE_PATH></values></conf1></gdb_debugger></sets></debugger_common><scripts><generic_wizard><WANT_DEBUG bool="1" /><DEBUG_NAME><str><![CDATA[Debug]]></str></DEBUG_NAME>
<DEBUG_OUTPUT><str /></DEBUG_OUTPUT><DEBUG_OBJECTS_OUTPUT><str /></DEBUG_OBJECTS_OUTPUT><WANT_RELEASE bool="1" /><RELEASE_NAME><str><![CDATA[Release]]></str></RELEASE_NAME><RELEASE_OUTPUT><str /></RELEASE_OUTPUT><RELEASE_OBJECTS_OUTPUT><str /></RELEASE_OBJECTS_OUTPUT></generic_wizard></scripts></CodeBlocksConfig>
'@).Save($confFile)
}
}
function Update-CData {
param(
[Parameter(Mandatory = $True, Position = 0)][xml]$oXML,
[Parameter(Mandatory = $True, Position = 1)][string]$baseNode,
[Parameter(Mandatory = $True, Position = 2)][string]$data
)
PROCESS {
$oNode = $oXML.DocumentElement.SelectSingleNode("${baseNode}/str")
if ($oNode) { $oNode.ParentNode.RemoveChild($oNode) | Out-Null }
$oItem = $oXML.CreateElement('str')
$oNode = $oXML.DocumentElement.SelectSingleNode($baseNode)
$oNode.AppendChild($oItem) | Out-Null
$oNode = $oXML.DocumentElement.SelectSingleNode("${baseNode}/str")
$oItem = $oXML.createCDATASection($data)
$oNode.AppendChild($oItem) | Out-Null
}
}
function Clear-Node {
param(
[Parameter(Mandatory = $True, Position = 0)][xml]$oXML,
[Parameter(Mandatory = $True, Position = 1)][string]$baseNode,
[Parameter(Mandatory = $True, Position = 2)][string]$node
)
PROCESS {
$oNode = $oXML.DocumentElement.SelectSingleNode("${baseNode}/$node")
if ($oNode) { $oNode.ParentNode.RemoveChild($oNode) | Out-Null }
$oNode = $oXML.DocumentElement.SelectSingleNode($baseNode)
$oItem = $oXML.CreateElement($node)
$oNode.AppendChild($oItem) | Out-Null
}
}
function Update-Recents {
param(
[Parameter(Mandatory = $True, Position = 0)][xml]$oXML,
[Parameter(Mandatory = $True, Position = 1)][string[]]$recentProjList
)
PROCESS {
$i = 0
$oNode = $oXML.DocumentElement.SelectSingleNode('app/RECENT_PROJECTS/astr')
$recentProjList | ForEach-Object {
$oItem = $oXML.CreateElement('s')
$oNode.AppendChild($oItem) | Out-Null
$oItem = $oXML.createCDATASection($_)
$oNode.ChildNodes[$i++].AppendChild($oItem) | Out-Null
}
}
}
function Update-Conf {
param(
[Parameter(Mandatory = $True, Position = 0)][string]$fileName,
[Parameter(Mandatory = $True, Position = 1)][string]$mingwDir,
[Parameter(Mandatory = $True, Position = 2)][string]$gdb,
[Parameter(Mandatory = $True, Position = 3)][string]$compilerName,
[Parameter(Mandatory = $True, Position = 4)][AllowNull()][string[]]$recentProjList
)
PROCESS {
$oXML = New-Object 'xml'
$oXML.Load($fileName)
Update-CData $oXML 'compiler/sets/gcc/MASTER_PATH' $mingwDir
Update-CData $oXML 'debugger_common/sets/gdb_debugger/conf1/values/EXECUTABLE_PATH' $gdb
Update-CData $oXML 'project_manager/DEFAULT_PATH' "${script:projDir}\"
Clear-Node $oXML 'compiler/sets/gcc' 'INCLUDE_DIRS'
Update-CData $oXML 'compiler/sets/gcc/INCLUDE_DIRS' "${mingwDir}\mingw\include;${script:aInclDir};"
Clear-Node $oXML 'compiler/sets/gcc' 'LIBRARY_DIRS'
Update-CData $oXML 'compiler/sets/gcc/LIBRARY_DIRS' "${mingwDir}\mingw\lib;"
Update-CData $oXML 'scripts/generic_wizard/DEBUG_OUTPUT' "bin\Debug_${compilerName}\"
Update-CData $oXML 'scripts/generic_wizard/DEBUG_OBJECTS_OUTPUT' "obj\Debug_${compilerName}\"
Update-CData $oXML 'scripts/generic_wizard/RELEASE_OUTPUT' "bin\Release_${compilerName}\"
Update-CData $oXML 'scripts/generic_wizard/RELEASE_OBJECTS_OUTPUT' "obj\Release_${compilerName}\"
Clear-Node $oXML 'app/RECENT_PROJECTS' 'astr'
if ($recentProjList) { Update-Recents $oXML $recentProjList }
$oXML.Save($fileName)
}
}
function Update-ProjFile {
param(
[Parameter(Mandatory = $True, Position = 0)][string]$fileName,
[Parameter(Mandatory = $True, Position = 1)][string]$compilerName
)
PROCESS {
$xml = New-Object 'xml'
$xml.Load($fileName)
$buildTarget = $xml.CodeBlocks_project_file.Project.Build.Target
$debug = $buildTarget | Where-Object { $_.title -eq 'Debug' }
$debugOptionOutput = $debug.Option | Where-Object { $_.HasAttribute('output') }
$debugOptionOutput.output = "bin/Debug_${compilerName}/$(Split-Path $debugOptionOutput.output -Leaf)"
$debugOptionObject_output = $debug.Option | Where-Object { $_.HasAttribute('object_output') }
$debugOptionObject_output.object_output = "obj/Debug_${compilerName}/"
$release = $buildTarget | Where-Object { $_.title -eq 'Release' }
$releaseOptionOutput = $release.Option | Where-Object { $_.HasAttribute('output') }
$releaseOptionOutput.output = "bin/Release_${compilerName}/$(Split-Path $releaseOptionOutput.output -Leaf)"
$releaseOptionObject_output = $release.Option | Where-Object { $_.HasAttribute('object_output') }
$releaseOptionObject_output.object_output = "obj/Release_${compilerName}/"
$xml.Save($fileName)
}
}
function Get-RecentProjects {
$projFiles = [Collections.Generic.List[string]]::new()
Get-ChildItem $script:projDir -Exclude '_archive_' -Directory -ErrorAction 'SilentlyContinue' | Get-ChildItem -Filter '*.layout' -Recurse -File -ErrorAction 'SilentlyContinue' | Sort-Object -Property 'LastWriteTime' -Descending -ErrorAction 'SilentlyContinue' | ForEach-Object { $projFiles.Add([IO.Path]::ChangeExtension($_.FullName, 'cbp')) }
$projFiles
}
function Get-CompilerList {
$compilers = [Collections.Generic.SortedList[string, object]]::new()
Get-ChildItem $script:cbDir -Directory | Sort-Object -Property 'Name' | Where-Object { $_.Name -match '^llvm-mingw-(\d{8})-(.+)' } | ForEach-Object { $compilers[$matches[2]] = @{ 'timestamp' = $matches[1]; 'path' = $_.FullName } }
$compilers
}
function Get-MatchingCompilerKey {
param(
[Parameter(Mandatory = $True)][string[]]$compilerKeys
)
PROCESS {
$archPatterns = @{ '0' = '-i686$'; '5' = '-armv7$'; '9' = '-x86_64$'; '12' = '-aarch64$' }
$systemInfo = [Int16[]]::new(32) # more than enough memory to alias a SYSTEM_INFO structure
[P.Invoke]::GetNativeSystemInfo($systemInfo)
$pattern = $archPatterns[[string]$systemInfo[0]] # the first element contains the SYSTEM_INFO::wProcessorArchitecture member
if (-not $pattern) { return $compilerKeys | Select-Object -First 1 }
$matching = $compilerKeys | Where-Object { $_ -match $pattern } | Select-Object -First 1
if (-not $matching) { return $compilerKeys | Select-Object -First 1 }
$matching
}
}
function Get-LatestOnlineCompilerTimestamp {
try {
$oHttpReq = [Net.HttpWebRequest]::Create($script:urlLatest)
$oHttpReq.AllowAutoRedirect = $False
$oHttpReq.Method = 'HEAD'
$response = $oHttpReq.GetResponse()
if ($response.StatusCode -eq 'Redirect') { $timeStamp = Split-Path $response.Headers['Location'] -Leaf }
$oHttpReq.Abort()
$response.Close()
$timeStamp
}
catch {}
}
function Resolve-RelativePath {
param(
[Parameter(Mandatory = $True)][string]$relPath
)
PROCESS {
$relPath = $relPath.Trim()
if (-not (Test-Path $relPath)) { return '' }
(Resolve-Path $relPath).Path
}
}
function Get-PickedFolder {
param(
[Parameter(Mandatory = $True)][string]$msg
)
PROCESS {
$oDir = (New-Object -ComObject 'Shell.Application').BrowseForFolder($script:hWnd, $msg, 0x201 <# BIF_RETURNONLYFSDIRS | BIF_NONEWFOLDERBUTTON #>, $PWD.Path)
if (-not $oDir) { return '' }
$oDir.Self.Path
}
}
function Update-GUI {
if (Test-ErrFlag $script:errCbDir) { $script:cbTxtBx.Text = '' }
else {
$script:cbTxtBx.Text = Resolve-Path $script:cbDir -Relative
if (Test-ErrFlag $script:errComp) {
$script:compilerList = Get-CompilerList
if ($script:compilerList.Count) {
Clear-ErrFlag $script:errComp
$script:compCoBx.ItemsSource = $script:compilerList.Keys
$script:compCoBx.SelectedItem = Get-MatchingCompilerKey $script:compilerList.Keys
$script:latestTimestamp = Get-LatestOnlineCompilerTimestamp
}
}
if (Test-ErrFlag $script:errCbExe) {
$script:cbExe = Join-Path $script:cbDir 'codeblocks.exe'
if (Test-Path $script:cbExe) {
Clear-ErrFlag $script:errCbExe
$script:mainWnd.Icon = [Windows.Interop.Imaging]::CreateBitmapSourceFromHIcon([Drawing.Icon]::ExtractAssociatedIcon($script:cbExe).Handle, [Windows.Int32Rect]::Empty, [Windows.Media.Imaging.BitmapSizeOptions]::FromEmptyOptions())
}
}
}
$script:projTxtBx.Text = $(if (Test-ErrFlag $script:errProjDir) { '' } else { Resolve-Path $script:projDir -Relative })
$script:aInclTxtBx.Text = $(if (Test-ErrFlag $script:errAInclDir) { '' } else { Resolve-Path $script:aInclDir -Relative })
$script:stsLnk.Text = ''
if ($script:errFlags) {
$script:startBtn.IsEnabled = $False
$script:stsTxt.Foreground = 'Red'
if (Test-ErrFlag $script:errCbDir) { $script:stsTxt.Text = $script:sId_10 }
elseif (Test-ErrFlag $script:errProjDir) { $script:stsTxt.Text = $script:sId_11 }
elseif (Test-ErrFlag $script:errAInclDir) { $script:stsTxt.Text = $script:sId_12 }
elseif (Test-ErrFlag $script:errCbExe) { $script:stsTxt.Text = $script:sId_13 }
else {
$script:stsTxt.Text = "${script:sId_14}`n"
$script:stsLnk.Text = $script:urlLatest
}
}
else {
$script:startBtn.IsEnabled = $True
$script:stsTxt.Foreground = 'White'
if ($script:latestTimestamp -gt $script:compilerList[$script:compCoBx.SelectedItem].timestamp) {
$script:stsTxt.Text = "${script:sId_15}`n"
$script:stsLnk.Text = $script:urlLatest
}
else { $script:stsTxt.Text = $script:sId_16 }
}
}
#region housekeeping
[void][P.Invoke]::ShowWindowAsync([P.Invoke]::GetConsoleWindow(), 0 <#SW_HIDE#>) # Try to hide the CLI as we only use the GUI.
try { [void][P.Invoke]::SetProcessDpiAwareness(2 <#PROCESS_PER_MONITOR_DPI_AWARE#>) } catch {} # Avoid blurry text.
Set-Location $script:scriptDir # However this script is invoked, make sure the current working directory is the script directory.
if (-not (Test-Path $script:prtblConf)) { New-PrtblConf }
$script:xmlConf = New-Object 'xml'
$script:xmlConf.Load($script:prtblConf)
if ($script:xmlConf.CB_Portable_Launcher_Config.Version -ne '2') { New-PrtblConf }
$script:cbDir = Resolve-RelativePath $script:xmlConf.CB_Portable_Launcher_Config.relative_paths.CBDir.'#cdata-section'
if ($script:cbDir) { Clear-ErrFlag $script:errCbDir }
$script:projDir = Resolve-RelativePath $script:xmlConf.CB_Portable_Launcher_Config.relative_paths.ProjDir.'#cdata-section'
if ($script:projDir) { Clear-ErrFlag $script:errProjDir }
$script:aInclDir = Resolve-RelativePath $script:xmlConf.CB_Portable_Launcher_Config.relative_paths.AdditionalIncludeDir.'#cdata-section'
if ($script:aInclDir) { Clear-ErrFlag $script:errAInclDir }
& {
if (Test-Path $script:i18nSpec) {
$langName = [Globalization.CultureInfo]::CurrentUICulture.Name -replace '-', '_'
$xmlLocl = New-Object 'xml'
$xmlLocl.Load($script:i18nSpec)
$sNodes = $xmlLocl.lang.$langName | Select-Object -First 1 | ForEach-Object { $_.s }
if (-not $sNodes) { $sNodes = $xmlLocl.lang.($langName -replace '_.*') | Select-Object -First 1 | ForEach-Object { $_.s } }
if (-not $sNodes) { $sNodes = $xmlLocl.lang.ChildNodes | Where-Object { $_.get_name() -like ($langName -replace '_.*', '_*') } | Select-Object -First 1 | ForEach-Object { $_.s } }
if ($sNodes) { $sNodes | ForEach-Object { Set-Variable "sId_$($_.id)" $_.'#cdata-section' -Scope 'Script' } }
}
else { New-I18nFile }
}
#endregion housekeeping
#region GUI elements
$script:mainWnd = [Windows.Markup.XamlReader]::Parse(@"
<Window xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Code::Blocks Portable Launcher" FocusManager.FocusedElement="{Binding ElementName=compCoBx}" ResizeMode="CanMinimize" SizeToContent="WidthAndHeight">
<Window.Resources>
<x:Double x:Key="CSpc">20</x:Double><x:Double x:Key="C1">180</x:Double><x:Double x:Key="C3">95</x:Double><x:Double x:Key="C6">75</x:Double>
<x:Double x:Key="RSpcN">3</x:Double><x:Double x:Key="RSpcW">8</x:Double><x:Double x:Key="RStc">30</x:Double><x:Double x:Key="RBox">26</x:Double><x:Double x:Key="RSts">55</x:Double>
<x:Double x:Key="LabelFontSize">12</x:Double><x:Double x:Key="BoxFontSize">14</x:Double>
<Color x:Key="AnthraciteBlack">#0f1012</Color><Color x:Key="AnthraciteShade">#1f2023</Color><Color x:Key="AnthraciteTint">#3f4144</Color>
<SolidColorBrush x:Key="AnthraciteBlackBrush" Color="{StaticResource AnthraciteBlack}" />
<SolidColorBrush x:Key="AnthraciteShadeBrush" Color="{StaticResource AnthraciteShade}" />
<LinearGradientBrush x:Key="AnthraciteGradientBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="{StaticResource AnthraciteShade}" Offset="0.0" /><GradientStop Color="{StaticResource AnthraciteTint}" Offset="1.0" />
</LinearGradientBrush>
<Style x:Key="LabelStyle" TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource LabelFontSize}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="VerticalAlignment" Value="Bottom" />
</Style>
<Style x:Key="TextBoxStyle" TargetType="TextBox">
<Setter Property="FontSize" Value="{StaticResource BoxFontSize}" />
<Setter Property="Background" Value="WhiteSmoke" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="IsReadOnly" Value="True" />
<Setter Property="IsTabStop" Value="False" />
</Style>
<Style x:Key="ButtonStyle" TargetType="Button">
<Setter Property="FontSize" Value="{StaticResource BoxFontSize}" />
<Setter Property="FontWeight" Value="Bold" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{StaticResource AnthraciteShadeBrush}" />
<Style.Resources>
<Style TargetType="Border"><Setter Property="CornerRadius" Value="5" /></Style>
</Style.Resources>
<Style.Triggers>
<Trigger Property="IsFocused" Value="True"><Setter Property="BorderBrush" Value="WhiteSmoke" /></Trigger>
<Trigger Property="IsMouseOver" Value="True"><Setter Property="Foreground" Value="Black" /></Trigger>
</Style.Triggers>
</Style>
<Style x:Key="StatusStyle" TargetType="Label">
<Setter Property="FontSize" Value="{StaticResource LabelFontSize}" />
<Setter Property="Foreground" Value="White" />
<Setter Property="Background" Value="{StaticResource AnthraciteBlackBrush}" />
<Setter Property="VerticalContentAlignment" Value="Center" />
<Setter Property="Padding" Value="20,0,20,0" />
</Style>
</Window.Resources>
<Grid Background="{StaticResource AnthraciteGradientBrush}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding Source={StaticResource CSpc}}" />
<ColumnDefinition Width="{Binding Source={StaticResource C1}}" />
<ColumnDefinition Width="{Binding Source={StaticResource CSpc}}" />
<ColumnDefinition Width="{Binding Source={StaticResource C3}}" />
<ColumnDefinition Width="{Binding Source={StaticResource CSpc}}" />
<ColumnDefinition Width="{Binding Source={StaticResource CSpc}}" />
<ColumnDefinition Width="{Binding Source={StaticResource C6}}" />
<ColumnDefinition Width="{Binding Source={StaticResource CSpc}}" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="{Binding Source={StaticResource RStc}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcN}}" />
<RowDefinition Height="{Binding Source={StaticResource RBox}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcW}}" />
<RowDefinition Height="{Binding Source={StaticResource RStc}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcN}}" />
<RowDefinition Height="{Binding Source={StaticResource RBox}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcW}}" />
<RowDefinition Height="{Binding Source={StaticResource RStc}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcN}}" />
<RowDefinition Height="{Binding Source={StaticResource RBox}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcW}}" />
<RowDefinition Height="{Binding Source={StaticResource RStc}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcN}}" />
<RowDefinition Height="{Binding Source={StaticResource RBox}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcW}}" />
<RowDefinition Height="{Binding Source={StaticResource RSpcW}}" />
<RowDefinition Height="{Binding Source={StaticResource RSts}}" />
</Grid.RowDefinitions>
<Label Content="$script:sId_0" Grid.Column="1" Grid.ColumnSpan="6" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="cbTxtBx" Grid.Column="1" Grid.Row="2" Grid.ColumnSpan="4" Style="{StaticResource TextBoxStyle}" />
<Button x:Name="cbBtn" Content="..." Grid.Column="6" Grid.Row="2" Style="{StaticResource ButtonStyle}" />
<Label Content="$script:sId_1" Grid.Column="1" Grid.Row="4" Grid.ColumnSpan="6" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="projTxtBx" Grid.Column="1" Grid.Row="6" Grid.ColumnSpan="4" Style="{StaticResource TextBoxStyle}" />
<Button x:Name="projBtn" Content="..." Grid.Column="6" Grid.Row="6" Style="{StaticResource ButtonStyle}" />
<Label Content="$script:sId_2" Grid.Column="1" Grid.Row="8" Grid.ColumnSpan="6" Style="{StaticResource LabelStyle}" />
<TextBox x:Name="aInclTxtBx" Grid.Column="1" Grid.Row="10" Grid.ColumnSpan="4" Style="{StaticResource TextBoxStyle}" />
<Button x:Name="aInclBtn" Content="..." Grid.Column="6" Grid.Row="10" Style="{StaticResource ButtonStyle}" />
<Label Content="$script:sId_3" Grid.Column="1" Grid.Row="12" Grid.ColumnSpan="2" Style="{StaticResource LabelStyle}" />
<ComboBox x:Name="compCoBx" Grid.Column="1" Grid.Row="14" FontSize="{StaticResource BoxFontSize}" VerticalContentAlignment="Center" />
<Button x:Name="startBtn" Content="$script:sId_4" IsDefault="True" Grid.Column="3" Grid.Row="13" Grid.RowSpan="3" Style="{StaticResource ButtonStyle}" />
<Button x:Name="cancelBtn" Content="$script:sId_5" IsCancel="True" Grid.Column="5" Grid.Row="13" Grid.ColumnSpan="2" Grid.RowSpan="3" Style="{StaticResource ButtonStyle}" />
<Label Grid.Row="17" Grid.ColumnSpan="8" Style="{StaticResource StatusStyle}">
<TextBlock TextWrapping="Wrap"><Run x:Name="stsTxt" /><Hyperlink Focusable="False"><Run x:Name="stsLnk" /></Hyperlink></TextBlock>
</Label>
</Grid>
</Window>
"@)
$script:hWnd = [Windows.Interop.WindowInteropHelper]::new($script:mainWnd).EnsureHandle()
'cbTxtBx', 'cbBtn', 'projTxtBx', 'projBtn', 'aInclTxtBx', 'aInclBtn', 'compCoBx', 'startBtn', 'cancelBtn', 'stsTxt', 'stsLnk' | ForEach-Object { Set-Variable $_ $script:mainWnd.FindName($_) -Scope 'Script' }
Update-GUI
#endregion GUI elements
#region GUI event handling
$updateAppearance = {
$Win32_TRUE = 1
[void][P.Invoke]::DwmSetWindowAttribute($script:hWnd, 20 <#DWMWA_USE_IMMERSIVE_DARK_MODE#>, [ref]$Win32_TRUE, 4 <#SizeOf($Win32_TRUE)#>) # dark title bar
[P.Invoke]::UpdateAppUserModel($script:hWnd) # equip the window with an own AppUserModel ID so that the window icon becomes the taskbar icon
}
$pickFolder = {
switch ($this.Name) {
'cbBtn' {
$script:cbDir = Get-PickedFolder $script:sId_6
Set-ErrFlag ($script:errCbExe -bOr $script:errComp)
$script:compilerList = $script:compCoBx.ItemsSource = $null
if ($script:cbDir) { Clear-ErrFlag $script:errCbDir } else { Set-ErrFlag $script:errCbDir }
break
}
'projBtn' {
$script:projDir = Get-PickedFolder $script:sId_7
if ($script:projDir) { Clear-ErrFlag $script:errProjDir } else { Set-ErrFlag $script:errProjDir }
break
}
'aInclBtn' {
$script:aInclDir = Get-PickedFolder $script:sId_8
if ($script:aInclDir) { Clear-ErrFlag $script:errAInclDir } else { Set-ErrFlag $script:errAInclDir }
}
}
Update-GUI
}
$execMain = {
if ((Get-Process 'codeblocks' -ErrorAction 'SilentlyContinue').Count) {
$script:stsTxt.Foreground = 'Red'
$script:stsTxt.Text = $script:sId_9
$script:stsLnk.Text = ''
}
else {
$script:xmlConf.CB_Portable_Launcher_Config.relative_paths.CBDir.'#cdata-section' = $script:cbTxtBx.Text
$script:xmlConf.CB_Portable_Launcher_Config.relative_paths.ProjDir.'#cdata-section' = $script:projTxtBx.Text
$script:xmlConf.CB_Portable_Launcher_Config.relative_paths.AdditionalIncludeDir.'#cdata-section' = $script:aInclTxtBx.Text
$script:xmlConf.Save($script:prtblConf)
$appdataDir = Join-Path $script:cbDir 'AppData'
$confFile = Join-Path $appdataDir 'codeblocks\default.conf'
if (-not (Test-Path $confFile)) {
New-Item (Join-Path $appdataDir 'codeblocks') -ItemType 'Directory' -Force
New-ConfFile $confFile
}
$selectedComp = $script:compCoBx.SelectedItem
$mingwDir = $script:compilerList[$selectedComp].path
$gdb = 'gdb.exe'
if ($selectedComp -match '-i686$') { $gdb = Join-Path $script:cbDir 'gdb\i686\bin\gdb.exe' }
elseif ($selectedComp -match '-x86_64$') { $gdb = Join-Path $script:cbDir 'gdb\x86_64\bin\gdb.exe' }
$recentProjs = Get-RecentProjects
Update-Conf $confFile $mingwDir $gdb $selectedComp ($recentProjs | Select-Object -First 20)
$env:APPDATA = $appdataDir
Start-Process $script:cbExe
$recentProjs | ForEach-Object { Update-ProjFile $_ $selectedComp }
$script:mainWnd.Close()
}
}
$script:mainWnd.Add_Loaded($updateAppearance)
$script:cbBtn.Add_Click($pickFolder)
$script:projBtn.Add_Click($pickFolder)
$script:aInclBtn.Add_Click($pickFolder)
$script:startBtn.Add_Click($execMain)
$script:cancelBtn.Add_Click({ $script:mainWnd.Close() })
$script:stsLnk.Add_PreviewMouseLeftButtonDown({ Start-Process $this.Text })
#endregion GUI event handling
[void]$script:mainWnd.ShowDialog()
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
│ ├─ llvm-mingw-20231031-msvcrt-i686
│ ├─ llvm-mingw-20231031-msvcrt-x86_64
│ ├─ share
│ └─ (codeblocks.exe)
│
├─ Projects
└─ (CB-Portable-Launcher.ps1)
5.1.1. Script speichern - How To
Wie ich erfahren habe, fällt es manch einem schwer den Code aus dem Forum als PowerShell Script abzuspeichern.- Den gesamten Code markieren und kopieren ([Strg]+[C]).
- Den Windows Editor öffnen. Bspw. so:
- Tastenkombination [Windows]+[R],
- notepad in den geöffneten "Ausführen" Dialog schreiben,
- OK anklicken.
- Den kopierten Code einfügen ([Strg]+[V]).
- Menü Datei -> Speichern unter...
- In das CodeBlocksPortable Verzeichnis navigieren
- Dateityp Alle Dateien (*.*) auswählen, Dateiname CB-Portable-Launcher.ps1
- Speichern.
5.2. Der erste Start
Nun ist alles für den ersten Run bereit. Je nach lokalen Einstellungen wird das Script über Kontextmenü der Datei oder durch Doppelklick auf "CB-Portable-Launcher.ps1" gestartet. Dieses prüft zunächst die Umgebung und wird feststellen, dass noch Dateien und Verzeichnisse fehlen. Kein Problem, du wirst durch die nächsten Schritte geführt.Klicke auf den ersten [...] Button. Du wirst nach dem "CodeBlocks" Verzeichnis gefragt. Dieses wählst du aus und bestätigst. Das gleiche mit den beiden weiteren [...] Buttons für die Verzeichnisse "Projects" und "Additional_Include".
Klicke auf den [Start] Button.
Code::Blocks öffnet sich nun und belästigt dich noch einmal damit, den Default Compiler "GNU GCC Compiler" zu bestätigen.
Achtung! Diese Meldung ist ggf. hinter anderen geöffneten Fenstern versteckt, sodass es den Anschein hat, Code::Blocks würde nicht starten. Minimiere in diesem Fall nacheinander alle geöffneten Fenster (oder navigiere bei gehaltener [Alt] Taste mit [Tab] durch die Fenster) ...
(Diese Prozedur gibt es wirklich nur beim ersten Start.)
Geschafft! Nun kannst du endlich loslegen ...
6. CB-Portable-I18n.xml
Diese Datei ist automatisch im CodeBlocksPortable Verzeichnis erstellt worden. Das "I18n" im Dateiname ist die übliche Abkürzung für "Internationalization". Sie enthält, neben einer kurzen Erklärung wie Übersetzungen hinzugefügt werden können, die englischen Bezeichnungen für Eingabefelder, Buttons, Prompts und Statusmeldungen. Natürlich stelle ich euch in einem deutschen Forum auch die deutschen Übersetzungen zur Verfügung. Öffne die Datei in einem Texteditor deiner Wahl und ersetze den Dateiinhalt durch folgenden:<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<lang>
<!--
To add a new translation, use either the long or short form of the language
code as child-node name of the 'lang' root node. Each of the forms must be
based on a 'CurrentUICulture.Name' property of the .NET class
'System.Globalization.CultureInfo'.
- The long form consists of the combination of the 2 letters for the
language, an underscore, and the country/region code.
NOTE: The hyphen of the 'CurrentUICulture.Name' property is replaced with
an underscore to get a valid node name.
Example: 'zh_Hans' or 'zh_Hant'
- The short form is only the 2 letters for the language. Prefer this form if
there are no differences in translation for countries or regions that use
the same language.
Example: 'de' (instead of 'de_AT', 'de_DE' etc.)
Search order:
- The long form is found.
- Else, the short form is found.
- Else, a long form with the same language but different country/region code
is found.
- Else, fall back to English.
Make sure
- to use CDATA elemets for translated strings,
- to save the file UTF-8 encoded.
-->
<en>
<s id="0"><![CDATA[CodeBlocks and compiler directory]]></s>
<s id="1"><![CDATA[Projects directory]]></s>
<s id="2"><![CDATA[Directory for additional header files]]></s>
<s id="3"><![CDATA[Compiler]]></s>
<s id="4"><![CDATA[Start]]></s>
<s id="5"><![CDATA[Cancel]]></s>
<s id="6"><![CDATA[Please select the Code::Blocks directory.]]></s>
<s id="7"><![CDATA[Please select the Projects directory.]]></s>
<s id="8"><![CDATA[Please select the Additional_Include directory.]]></s>
<s id="9"><![CDATA["Code::Blocks" has already been started in another process.
Close the "Code::Blocks" window and try again.]]></s>
<s id="10"><![CDATA[Error! Select the "CodeBlocks and compiler directory".]]></s>
<s id="11"><![CDATA[Error! Select the "Projects directory".]]></s>
<s id="12"><![CDATA[Error! Select the "Directory for additional header files".]]></s>
<s id="13"><![CDATA[The file "codeblocks.exe" was not found.
Check your selection in the "CodeBlocks and compiler directory" box.]]></s>
<s id="14"><![CDATA[Error! No compiler found. Visit]]></s>
<s id="15"><![CDATA[Ready. - There is a new compiler version. Visit]]></s>
<s id="16"><![CDATA[Ready. - If necessary, select the compiler for the target platform.]]></s>
</en>
<de>
<s id="0"><![CDATA[CodeBlocks- und Compilerverzeichnis]]></s>
<s id="1"><![CDATA[Projektverzeichnis]]></s>
<s id="2"><![CDATA[Verzeichnis für zusätzliche Headers]]></s>
<s id="3"><![CDATA[Compiler]]></s>
<s id="4"><![CDATA[Starten]]></s>
<s id="5"><![CDATA[Abbrechen]]></s>
<s id="6"><![CDATA[Bitte wählen Sie das Code::Blocks-Verzeichnis aus.]]></s>
<s id="7"><![CDATA[Bitte wählen Sie das Projects-Verzeichnis aus.]]></s>
<s id="8"><![CDATA[Bitte wählen Sie das Additional_Include-Verzeichnis aus.]]></s>
<s id="9"><![CDATA["Code::Blocks" wurde bereits in einem anderen Prozess gestartet.
Schließen Sie das "Code::Blocks" Fenster und versuchen Sie es erneut.]]></s>
<s id="10"><![CDATA[Fehler! Wählen Sie das "CodeBlocks- und Compilerverzeichnis" aus.]]></s>
<s id="11"><![CDATA[Fehler! Wählen Sie das "Projektverzeichnis" aus.]]></s>
<s id="12"><![CDATA[Fehler! Wählen Sie das "Verzeichnis für zusätzliche Headers" aus.]]></s>
<s id="13"><![CDATA[Die Datei "codeblocks.exe" wurde nicht gefunden.
Überprüfen Sie ihre Auswahl im Feld "CodeBlocks- und Compilerverzeichnis".]]></s>
<s id="14"><![CDATA[Fehler! Kein Compiler gefunden. Besuchen Sie]]></s>
<s id="15"><![CDATA[Bereit. - Es liegt eine neue Compilerversion vor. Besuchen Sie]]></s>
<s id="16"><![CDATA[Bereit. - Wählen Sie ggf. den Compiler für die Zielplattform aus.]]></s>
</de>
</lang>
Ich habe ein GitHub Repository für diese Datei erstellt. Nutzer sind herzlich eingeladen ihre Übersetzung in einem Pull Request beizutragen. Oder schreibt sie einfach in diesen Forum Thread und ich kümmere mich um den Rest
7. Weitere Informationen
7.1. Wie funktioniert das Script eigentlich?
Code::Blocks benötigt die Datei "default.conf", ein XML File welches sämtliche Einstellungen der IDE enthält. Diese Datei würde normalerweise im AppData Verzeichnis deines Benutzerprofils angelegt werden. Das Script erstellt zunächst einen Prototyp dieser Datei unter "CodeBlocksPortable\CodeBlocks\AppData\codeblocks" und speichert dort die Lage des Compilers, deiner Projekte und weitere Einstellungen. Diese Einstellungen werden bei jedem Start durch das Script aktualisiert. Weiterhin wird die Umgebungsvariable %AppData% für den codeblocks.exe Prozess dahingehend geändert, dass Code::Blocks die so veränderte "default.conf" lädt statt in deinem Benutzerprofil zu suchen. Code::Blocks wird in dieser Umgebung gestartet und mutiert somit zur "Portable App".Es werden auch compilerabhängige Target-Pfade für die kompilierten Apps genutzt. Dazu werden zusätzlich zur Änderung der "default.conf" auch in sämtlichen Projektdateien (*.cbp) im "Projects" Verzeichnis die entsprechenden Target-Pfade aktualisiert. Das hat den Vorteil, dass es nicht zu Fehlern für nicht neu kompilierte Dateien für eine andere Prozessorarchitektur kommt, sowie dass Executables im "bin" Verzeichnis für unterschiedliche Architekturen auch in unterschiedlichen, entsprechend benannten Unterverzeichnissen gespeichert werden. Damit die Projektdateien aktualisiert werden können, müssen die Projekte aber bereits bei Start des Scripts im "Projects" Verzeichnis liegen. Projekte im Unterverzeichnis "_archive_" (siehe Punkt 3.) sind von dieser Aktualisierung ausgeschlossen.
7.2. Warum kann ich auf einem 32-Bit System kein 64-Bit Programm erstellen?
Der Compiler für 64-Bit-Applikationen ist selbst ein 64-Bit-Programm. Das läuft natürlich nicht auf einem 32-Bit System.Umgekehrt funktioniert das aber. Du kannst 32-Bit-Programme unter einem 64-Bit Betriebssystem kompilieren. Aus diesem Grund ist im Launcher Dialog auswählbar, welcher Compiler heran gezogen werden soll.
7.3. Wie kann ich den Compiler auf aktuellem Stand halten?
Es gibt keine automatische Updatefunktion. Die Statuszeile des Launcher Dialogs gibt aber Auskunft darüber, wenn eine neue Compilerversion vorliegt. Verfahre dann wie in Punkt 4.2. beschrieben, um Verzeichnisse mit der neusten Version hinzuzufügen. Die alten Compilerverzeichnisse können gelöscht werden. Das Script sucht ohnehin nur nach der jeweils neusten Version.7.4. Wenn ein LLVM Toolset verwendet wird, warum ist GCC als Standardcompiler ausgewählt?
Ich muss zugeben, dass das tatsächlich widersprüchlich ist. Behandle "GCC" als Profilname, anstatt als Compilername in diesem Fall.Basierend auf der ursprünglichen Anleitung, gibt es sicher Leute die diese Lösung bereits seit Jahren nutzen. Um kompatibel mit einer existierenden "default.conf" zu bleiben, habe ich mich entschlossen beim Name "GCC" für dieses Profil zu bleiben. Das ist möglich, da die LLVM Toolsets leichtgewichtige Wrapper Apps nutzen, die lediglich unterschiedliche Namen haben. Inbegriffen sind auch die Namen des GCC Toolsets. Die Kommandozeilenoptionen sind auch weitestgehend kompatibel, somit nehme ich den Schönheitsfehler zugunsten der Beibehaltung von Einstellungen langjähriger Nutzer in Kauf.
7.5. Wie kann ich meine App in Code::Blocks debuggen?
Der Debugger ist eine beachtenswerte Ausnahme bei den oben genannten Toolnamen. Die gdb.exe ist nicht enthalten. Der LLVM Debugger ist lldb.exe. Allerdings ist dieser Debugger nicht mit Code::Blocks kompatibel. Für i686 und x86_64 Prozessoren gibt es aber GDB Builds für Windows.Ich habe mich für diese (github.com/ssbssa/gdb/releases/latest) entschieden.
Lade die Archive herunter, die den Mustern "gdb-<version>-i686.7z" und "gdb-<version>-x86_64.7z" entsprechen.
(z.B. gdb-14.1.90.20231204-i686.7z und gdb-14.1.90.20231204-x86_64.7z)
Lege den Ordner CodeBlocksPortable\CodeBlocks\gdb an. Dann dort die Unterverzeichnisse i686 und x86_64.
Kopiere die in den heruntergeladenen 7z Archiven enthaltenen bin Ordner in die entsprechenden Unterverzeichnisse.
Die Verzeichnisstruktur sollte nun so aussehen:
CodeBlocksPortable
├─ Additional_Include
├─ CodeBlocks
│ ├─ AppData
│ ├─ gdb
│ │ ├─ i686
│ │ │ └─ bin
│ │ │ └─ (gdb.exe)
│ │ └─ x86_64
│ │ └─ bin
│ │ └─ (gdb.exe)
│ ├─ llvm-mingw-20231031-msvcrt-i686
│ ├─ llvm-mingw-20231031-msvcrt-x86_64
│ ├─ share
│ └─ (codeblocks.exe)
│
├─ Projects
└─ (CB-Portable-Launcher.ps1)
7.6. Wie kann ich das GUI mit der Tastatur steuern?
Anfangs hat die Compiler Box den Tastaturfokus und der Start Button ist der Standardbutton.- Sollte der richtige Compiler bereits vorselektiert sein, ist das Drücken der [Enter] Taste alles was du tun musst, um Code::Blocks zu starten.
- Wenn ein anderer Compiler gewählt werden soll, nutze die Pfeiltasten [Up] und [Down] vor dem Drücken von [Enter]. Um das Dropdown auszuklappen, drücke die Tastenkombination [Alt]+[Down].
- Mit der [Tab] Taste kannst du zu den anderen interaktiven Elementen in der GUI navigieren. Der hervorgehobene Button bekommt den Tastaturfokus und du kannst die [Enter] Taste statt einem Mausklick nutzen.
Änderungen:
- 20.07.2024 Punkt 7.6. hinzugefügt.
- 23.02.2024 Script: Sicherstellen, dass die Zeichencodierung von XML Dateien beachtet wird.
- 04.02.2024 Script: Sicherstellen, dass der codeblocks.exe Pfad korrekt aktualisiert wird. Nutzung des C::B Icons.
- 18.12.2023 Punkt 7.5. für eine Option zum Debuggen hinzugefügt. Script aktualisiert, um sie zum Laufen zu bringen.
- 16.11.2023 Script: Sicherstellen, dass die Compilerliste korrekt aktualisiert wird.
- 15.11.2023 Script: Leicht aktualisierte Spaltenbreiten und Zeilenhöhen, um die Textlängen von Übersetzungen widerzuspiegeln.
- 14.11.2023 Script: Automatischer Zeilenumbruch in Status Bar hinzu, da längerer Text in Übersetzungen erwartet wird
- 12.11.2023 Punkt 6 GitHub Link ergänzt, Punkt 7.4. hinzugefügt
- 11.11.2023 Initiale Veröffentlichung als logischer Nachfolger von (obsolet) CodeBlocks Portable mit MinGW 32 und 64 Bit unter Windows
Please also mark the comments that contributed to the solution of the article
Content-ID: 12183097108
Url: https://administrator.de/contentid/12183097108
Printed on: November 11, 2024 at 21:11 o'clock
1 Comment