-
Notifications
You must be signed in to change notification settings - Fork 460
Add transition GUI to the E+ Auxiliary CLI #10967
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
Myoldmopar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Note - this will still execute the underlying Fortran based transition binaries. It just launches the Python GUI. IDFVersionUpdater is I think broken again on Ubuntu 24.04, so this would eliminate the need for that. I am open to removing it entirely in favor of this.
src/EnergyPlus/CMakeLists.txt
Outdated
| POST_BUILD # TODO: I don't think we want to quote the generator expression | ||
| COMMAND ${CMAKE_COMMAND} -E env --unset=PIP_REQUIRE_VIRTUALENV | ||
| ${Python_EXECUTABLE} -m pip install --target="$<TARGET_FILE_DIR:energyplusapi>/python_lib" --upgrade energyplus-launch==3.7.2 | ||
| ${Python_EXECUTABLE} -m pip install --target="$<TARGET_FILE_DIR:energyplusapi>/python_lib" --upgrade energyplus-launch==3.7.2 energyplus-transition-tools==2.1.1 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Just grab the transition tool package, at version 2.1.1 which I just released this morning after some cleanups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When do we start using https://github.com/Myoldmopar/EnergyPlusPythonApps/ as a meta package itself?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
|
|
||
| cmd += R"python( | ||
| from energyplus_transition.runner import main_gui | ||
| main_gui(True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the auxiliary updater keywords are passed to the E+ CLI, it will launch the transition GUI and leave. This could be modified later to like pass the IDF file in, but I truly don't think that's necessary. This is launching a GUI, no one should be integrated this auxiliary argument into some sort of automated workflow.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And yes, there is quite a bit of duplicate from the EP Launch code right above. Would be nice to collect things into the PythonEngine class and out of here. But doesn't have to be right now.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the auxiliary updater keywords are passed to the E+ CLI, it will launch the transition GUI and leave. This could be modified later to like pass the IDF file in, but I truly don't think that's necessary. This is launching a GUI, no one should be integrated this auxiliary argument into some sort of automated workflow.
It'd sure be nice if one could bypass the GUI and do something like energyplus auxiliary updater myfile.idf (potentially with a --up-to-version 24.2.0) to directly transition the file in the command line.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be great, let's do that soon.
|
@mjwitte Thank you!! OK, got nearly everything resolved for you.
I am going to kick off another test package with all this in it. Let me know if you find anything else! |
That makes me puzzled. There is no reason it would not be in the original dir, is there? If I run this transition_exe = Path('/path/to/EnergyPlus/PreProcess/IDFVersionUpdater/Transition-VXXX-to-VYYY')
subprocess.check_call([str(transition_exe), '/full/path/to/file.idf'], cwd=transition_exe.parent)Then the idf object is transition at its original location to begin with |
src/EnergyPlus/CMakeLists.txt
Outdated
| # NOTE: The install command COMPONENTS should line up so that they are run at the same packaging step | ||
| install(CODE "execute_process(COMMAND powershell.exe -ExecutionPolicy Bypass -File ${PROJECT_SOURCE_DIR}/scripts/dev/create_shortcut.ps1 -TargetPath \"$<TARGET_FILE:energyplus>\" -ShortcutPath \"$<TARGET_FILE_DIR:energyplus>/EPLaunchPython.lnk\" -Arguments \"auxiliary eplaunch\")" COMPONENT Auxiliary) | ||
| install(CODE "execute_process(COMMAND powershell.exe -ExecutionPolicy Bypass -File ${PROJECT_SOURCE_DIR}/scripts/dev/create_shortcut.ps1 -TargetPath \"$<TARGET_FILE:energyplus>\" -ShortcutPath \"$<TARGET_FILE_DIR:energyplus>/IDFVersionUpdater.lnk\" -Arguments \"auxiliary updater\")" COMPONENT Auxiliary) | ||
| install(FILES $<TARGET_FILE_DIR:energyplus>/EPLaunchPython.lnk DESTINATION "./" COMPONENT Auxiliary) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The IDFVersionUpdater shortcut is not there. Does it need a line like this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh sheesh. Yes. I've got another round of tweaks on the updater tool itself that I'm wrapping up and will tag/pin a new version, and update this here.
Thanks @Myoldmopar !
Getting there. Would prefer to see here: Need to cleanup all of these. VCPerr file is the audit from the first conversion, not sure where the other audit output is for the later conversions?
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think I'll plan on just naming this info.plist.in since it becomes info.plist.
|
So there is a ValueError saying that launcher.sh isn't signed. The launcher.sh is a minimal little bash script that goes inside the newly generated .app bundles for EPLaunch and VersionUpdater. I am not sure that those need to be signed, but I found the spot where other bash scripts (runenergyplus) were being signed, so I added it to that list. I'm not 100% sure how declaring the name there is enough, but it seems to work for runenergyplus and the others. Anxious to learn about how to address this properly since there will be more coming later. @jmarrec FYI and HELP! 😆 |
OK, so the install(signer script could not find the launcher.sh file. It looks like it is trying to find it in the packages/Unspecified/data folder. But I had used COMPONENT Auxiliary in the install( for the app bundle. I am kinda hopeful that maybe this will work. By not specifying a COMPONENT, it will end up in the Unspecified package to match the signer script. Let's see.
| }); | ||
|
|
||
| auto *updaterSubCommand = auxiliaryToolsSubcommand->add_subcommand("updater", "IDF Version Updater"); | ||
| updaterSubCommand->add_option("args", python_fwd_args, "Extra Arguments forwarded to IDF Version Updater")->option_text("ARG ..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What extra args does this accept? I'm confused.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't...for now. This could be considered future proofing and not hurt anything right now.
|
|
||
| cmd += R"python( | ||
| from energyplus_transition.runner import main_gui | ||
| main_gui(True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If the auxiliary updater keywords are passed to the E+ CLI, it will launch the transition GUI and leave. This could be modified later to like pass the IDF file in, but I truly don't think that's necessary. This is launching a GUI, no one should be integrated this auxiliary argument into some sort of automated workflow.
It'd sure be nice if one could bypass the GUI and do something like energyplus auxiliary updater myfile.idf (potentially with a --up-to-version 24.2.0) to directly transition the file in the command line.
cmake/Install.cmake
Outdated
| "runenergyplus" | ||
| "runepmacro" | ||
| "runreadvars" | ||
| "launcher.sh" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you need to sign the .app bundle itself.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think bash scripts really need to be signed?
In any case, your launcher.sh If I'm reading this PR correctly does NOT live at INSTALL_PATH/launcher.sh but at INSTALL_PATH/AppName.app/Contents/MacOS/launcher.sh, right?
…decent_ci_skip] [actions skip]
|
This is super close now. I'm glad CI is all clean, and all the package builds were successful. What I see now:
|
cmake/energyplus.desktop.in
Outdated
| Name=EnergyPlus ENERGYPLUS_VERSION | ||
| Comment=Run EnergyPlus Launch | ||
| Exec=ENERGYPLUS_INSTALL_DIR/energyplus auxiliary eplaunch | ||
| Exec=env LD_LIBRARY_PATH=ENERGYPLUS_INSTALL_DIR/python_lib/lib-dynload ENERGYPLUS_INSTALL_DIR/energyplus auxiliary eplaunch |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you're perhaps going about it the wrong way.
First, on mac, what we do is to:
- Copy the tcl libs
- Use
install_name_toolto change the_tkinter.soso look for these libs and NOT at/opt/homebrew/xxxx. See cmake/PythonFixUpTclTk.py - That way no need to mess with the LD_LIBRARY_PATH or anything
So at the very least, you should probably do the same with Linux.
(py312)(3.2.2)julien@EnergyPlus-build-release$ ldd Products/python_lib/lib-dynload/_tkinter.cpython-312-x86_64-linux-gnu.so
linux-vdso.so.1 (0x0000734351f28000)
+ libtk8.6.so => /lib/x86_64-linux-gnu/libtk8.6.so (0x0000734351d84000)
+ libtcl8.6.so => /lib/x86_64-linux-gnu/libtcl8.6.so (0x0000734351bd7000)
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x0000734351800000)
libXft.so.2 => /lib/x86_64-linux-gnu/libXft.so.2 (0x0000734351bbc000)
libfontconfig.so.1 => /lib/x86_64-linux-gnu/libfontconfig.so.1 (0x0000734351b6b000)
- libX11.so.6 => /lib/x86_64-linux-gnu/libX11.so.6 (0x0000734351a2c000)But Honestly, I don't see why we should ship libtk/libtcl any more than libX11 for eg.
On mac, there is a difference:
- You must have brew installed to brew install tcl-tk . Ubuntu users have
aptalready. - The newest brew recipe is incompatible, you have to specifically call
brew install tcl-tk@8
FWIW, in OpenStudio when we build the .deb installer, we do set the dependencies that are missing in E+:
set(CPACK_DEBIAN_PACKAGE_DEPENDS "libgomp1, libx11-6") # This is for EnergyPlusThere was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
EnergyPlus/cmake/PythonFixUpTclTk.py
Lines 117 to 142 in 4df1e4c
| tk_so = locate_tk_so(python_dir) | |
| tcl_tk_sos = [Path(t["libname"]) for t in get_linked_libraries(tk_so) if "libt" in t["libname"]] | |
| any_missing = False | |
| for tcl_tk_so in tcl_tk_sos: | |
| new_tcl_tk_so = lib_dynload_dir / tcl_tk_so.name | |
| if str(tcl_tk_so).startswith('@loader_path'): | |
| assert new_tcl_tk_so.is_file(), f"{new_tcl_tk_so} missing when the tkinter so is already adjusted. Wipe the dir" | |
| print("Already fixed up the libtcl and libtk, nothing to do here") | |
| continue | |
| elif not str(tcl_tk_so).startswith('@') and not tcl_tk_so.exists(): | |
| print(f"Hmmm... could not find the dependency shared object at {tcl_tk_so}; script will continue but fail") | |
| any_missing = True | |
| continue | |
| shutil.copy(tcl_tk_so, new_tcl_tk_so) | |
| # during testing, the brew installed tcl and tk libraries were installed without write permission | |
| # the workaround was to manually chmod u+w those files in the brew install folder | |
| # instead let's just fix them up once we copy them here | |
| current_perms = os.stat(str(new_tcl_tk_so)).st_mode | |
| os.chmod(str(new_tcl_tk_so), current_perms | stat.S_IWUSR) | |
| # now that it can definitely be written, we can run install_name_tool on it | |
| subprocess.check_output( | |
| ["install_name_tool", "-change", str(tcl_tk_so), f"@loader_path/{new_tcl_tk_so.name}", str(tk_so)] | |
| ) | |
| # Change the id that's the first line of the otool -L in this case and it's confusing | |
| subprocess.check_output(["install_name_tool", "-id", str(new_tcl_tk_so.name), str(new_tcl_tk_so)]) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One of my main goals is to continue to allow a non-sudo install of EnergyPlus on Linux. If the user doesn't want system symlinks, and wants to install it in a user-owned folder, they shouldn't need to follow up with sudo installing stuff. I am not going to die on that hill, but I will risk being injured on it. I have it working really well, so I think we should put 25.1 out there with this, and we can make a correction if needed as we go into the next version.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still a few things left to consider, but walkthrough is done.
Icons labeled and version numbered?- This isn't happening now. I want to get a version of E+ out the door, and get the full experience across all platforms, and then make improvements based on that. At a minimum, I suspect we'll end up making some new icons for EPLaunch vs VersionUpdater. And we may need to tweak the Python code for those to get the icons to behave really nicely. So this is for later.
add_custom_commands all need to identify their output files- I would still love this, but it needs a little work. The BYPRODUCTS cannot be target-specific generators, and we do a lot of target-specific stuff in the add_custom_commands related to Python. I definitely want to rethink that stuff but that's not today.
- .desktop should be part of uninstall
- patchelf instead of LD_LIBRARY_PATH
- remove IDFVersionUpdater classic? At least from Linux?
- Update documentation
-
Move IDFVersionUpdater shortcut into preprocess?- No, but I put a "VersionUpdater-NEWS.txt file in the PreProcess folder to help users find out about the new stuff
-
Remove the auxiliary.sh.in stuff on Linux, is it used?- For now I'm going to leave it because it allows a user to double click to launch the tools from the install folder. If we can get the LD_LIBRARY_PATH thing solved, then it may not be as needed. I will double check that we are creating similar names of these shortcuts in all platforms though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, so I'll do a walkthrough now. There are still a couple things left but it's very very close.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks to @jmarrec for getting these Python app bundles signed and packed up nicely. Things are working amazingly on Mac. I imagine we will want more of these as we add a few more apps (EpJSONEditor...)
|
|
||
| if (PYTHON_CLI) | ||
| cpack_ifw_configure_component(Unspecified SCRIPT cmake/qtifw/install_auxiliary_python_shortcuts.qs) | ||
| endif() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Alright, so here is a new QtIFW script that is attached to the Unspecified component. Could consider adding it to the Auxiliary or something if we wanted all the Python CLI app stuff in Auxiliary.
Anyway, this script will handle any desktop integration steps to enhance the user experience.
| if __name__ == "__main__": | ||
|
|
||
| if platform.system() != "Darwin": | ||
| if platform.system() != "Darwin" and platform.system() != 'Linux': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Now that we are packaging up the tcl and tk stuff for Ubuntu, we need to abort if we are not on one of those (so .... Windows 🙃 )
|
|
||
| if any_missing: | ||
| sys.exit(1) | ||
| if platform.system() == 'Darwin': |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
If we are on Mac, we haven't changed anything from 24.2. We still find the tk blobs, move things around, and run install_name_tool to get everyone happy.
| sys.exit(1) | ||
|
|
||
| elif platform.system() == 'Linux': | ||
| # On Linux, we need to copy the libtk.X.Y.so file from usually /usr/lib/x86_64-linux-gnu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Linux, we are currently getting the libtk library, plus the tcl and tk config/data directories and bringing them along. As it stands right now, on Linux you need to tell the process where to find libtk8.6.so in order to run the Python GUIs. This is hidden from the user through the desktop integration and setting LD_LIBRARY_PATH. But @jmarrec feels we should do a patchelf to fix up the _tkinter library instead. I'm on board, and this will likely be fixed up before merge. I will say, it does seem like everything is running happily though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed the patchelf stuff worked! Note that when you apt install python3-tk, you will get a _tkinter shared object library that is stripped of it's ELF section headers, and you cannot write an rpath into it. A warning has been added to GHA if it encounters this condition.
| install( | ||
| FILES ${PROJECT_SOURCE_DIR}/cmake/energyplus.desktop.in | ||
| DESTINATION share/applications | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On Linux we now need to create a couple shell scripts to launch EPLaunch and VersionUpdater right in the install root. On second thought, maybe these aren't needed? I'll consider removing them.
And we also now install a .desktop template inside install root / share/applications to be customized at install time by the QtIFW scripts.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to leave these little shortcuts in. I honestly doubt many people will ever use them on Linux. Either they will be happy on a terminal and just execute ./energyplus auxiliary eplaunch, or they will use the desktop integration and click on the E+ icon on the dock. But it's fine for now.
| }); | ||
|
|
||
| auto *updaterSubCommand = auxiliaryToolsSubcommand->add_subcommand("updater", "IDF Version Updater"); | ||
| updaterSubCommand->add_option("args", python_fwd_args, "Extra Arguments forwarded to IDF Version Updater")->option_text("ARG ..."); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
It doesn't...for now. This could be considered future proofing and not hurt anything right now.
|
|
||
| cmd += R"python( | ||
| from energyplus_transition.runner import main_gui | ||
| main_gui(True) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, that would be great, let's do that soon.
| cmd += fmt::format("environ[\'TCL_LIBRARY\'] = \"{}/{}\"\n", sPathToPythonPackages, tclConfigDir); | ||
| cmd += fmt::format("environ[\'TK_LIBRARY\'] = \"{}/{}\"\n", sPathToPythonPackages, tkConfigDir); | ||
| return cmd; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I was duplicating this for each GUI, so I made a worker function out of it.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is the worker function on Windows that can execute a script without opening a terminal. The shenanigans are at a all time high, but this works so perfectly. I'm quite happy with it.
| // Remove the executable name to get the directory | ||
| std::wstring directory(path); | ||
| size_t pos = directory.find_last_of(L"\\/"); | ||
| if (pos != std::wstring::npos) { | ||
| directory = directory.substr(0, pos); // Extract just the directory path | ||
| } | ||
|
|
||
| // Construct the target application path (assuming it's in the same directory) | ||
| std::wstring targetApp = directory + L"\\energyplus.exe"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
One could argue you should be using std::filesystem::path (which uses wchar_t on windows), instead of string manipulation. But you're already using Windows API, so screwed for screwed 🤷
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think you could call GetLastError to format the system error message. Untested:
diff --git a/src/EnergyPlus/WindowsGuiLauncher.cc b/src/EnergyPlus/WindowsGuiLauncher.cc
index 8d63d8b3f1..b8a007275a 100644
--- a/src/EnergyPlus/WindowsGuiLauncher.cc
+++ b/src/EnergyPlus/WindowsGuiLauncher.cc
@@ -45,30 +45,53 @@
// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
+#include <filesystem>
#include <string>
#include <windows.h>
+void ErrorExit()
+{
+ // Retrieve the system error message for the last-error code
+
+ LPVOID lpMsgBuf;
+ DWORD dw = GetLastError();
+
+ if (FormatMessageW(FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM | FORMAT_MESSAGE_IGNORE_INSERTS,
+ NULL,
+ dw,
+ MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
+ (LPWSTR)&lpMsgBuf,
+ 0,
+ NULL) == 0) {
+ MessageBoxW(NULL, TEXT("FormatMessage failed"), TEXT("Error"), MB_OK);
+ ExitProcess(dw);
+ }
+
+ MessageBoxW(NULL, (LPWSTR)lpMsgBuf, TEXT("Error"), MB_ICONERROR | MB_OK);
+
+ LocalFree(lpMsgBuf);
+ ExitProcess(dw);
+}
+
int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow)
{
+ using namespace fs = std::filesystem;
+
// Get the path of the current executable
- wchar_t path[MAX_PATH];
- if (GetModuleFileNameW(NULL, path, MAX_PATH) == 0) {
+ wchar_t c_path[MAX_PATH];
+ if (GetModuleFileNameW(NULL, c_path, MAX_PATH) == 0) {
MessageBoxW(NULL, L"Failed to get module file name!", L"Error", MB_ICONERROR | MB_OK);
return 1;
}
// Remove the executable name to get the directory
- std::wstring directory(path);
- size_t pos = directory.find_last_of(L"\\/");
- if (pos != std::wstring::npos) {
- directory = directory.substr(0, pos); // Extract just the directory path
- }
+ fs::path thisExePath(c_path);
+ fs::path thisDirPath = thisExePath.parent_path();
// Construct the target application path (assuming it's in the same directory)
- std::wstring targetApp = directory + L"\\energyplus.exe";
+ fs::path targetApp = thisDirPath / L"energyplus.exe";
- // Check if the file exists
- if (GetFileAttributesW(targetApp.c_str()) == INVALID_FILE_ATTRIBUTES) {
+ if (!fs::is_regular_file(targetApp)) {
MessageBoxW(NULL, L"Application not found!", L"Error", MB_ICONERROR | MB_OK);
return 1;
}
@@ -78,19 +101,19 @@ int wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int
args += lpCmdLine;
// Launch the target application
- HINSTANCE hInstance2 = ShellExecuteW(NULL, // Parent window
- L"open", // Operation
- targetApp.c_str(), // Executable path
- args.c_str(), // Arguments
- directory.c_str(), // Working directory
- SW_HIDE // Hide console
+ HINSTANCE hInstance2 = ShellExecuteW(NULL, // Parent window
+ L"open", // Operation
+ targetApp.c_str(), // Executable path
+ args.c_str(), // Arguments
+ thisDirPath.c_str(), // Working directory
+ SW_HIDE // Hide console
);
- // Error handling
+ // Error handling: https://learn.microsoft.com/en-us/windows/win32/api/shellapi/nf-shellapi-shellexecutew#return-value
if ((intptr_t)hInstance2 <= 32) {
std::wstring errorMsg = L"Failed to launch application! Error code: " + std::to_wstring((intptr_t)hInstance2);
MessageBoxW(NULL, errorMsg.c_str(), L"Error", MB_ICONERROR | MB_OK);
- return 1;
+ ErrorExit();
}
return 0;There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring this until later, but very happy to get this tested and integrated later.
…inux is happy then this just needs docs and merged.
|
And it is totally happy on Linux! I just need to know from @jmarrec if those Windows changes are worth pulling in or not. If not, then this could be ready to merge in. I think now I'll just defer any documentation changes until my very last PrepFor251 style branch where I update the README and all the other silly stuff. |
|
OK, and it seems that the Windows changes are not important right now. In the spirit of trying to get this in the hands of testers as soon as possible, I'm planning on merging this once CI finishes up, and tagging RC1. I will await testing results and start modifying documentation for these changes in the meantime. |
Myoldmopar
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
OK, that's it. Code walkthrough is done. Merging this in. If CI doesn't find anything in the normal develop testing, then I'll tag it as RC1 and start working on docs/release notes.
| echo "Using Apt to install dependencies" | ||
| sudo apt-get update | ||
| sudo apt-get install texlive texlive-xetex texlive-science libxkbcommon-x11-0 xorg-dev libgl1-mesa-dev | ||
| sudo apt-get install texlive texlive-xetex texlive-science libxkbcommon-x11-0 xorg-dev libgl1-mesa-dev patchelf |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Patchelf is used to edit the ELF header in the _tkinter shared object library on Linux, similar to install_name_tool on Mac.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Removed the IDFVersionUpdater for Linux....Windows and Mac are going to be gone with the next release.
| sys.exit(1) | ||
|
|
||
| elif platform.system() == 'Linux': | ||
| # On Linux, we need to copy the libtk.X.Y.so file from usually /usr/lib/x86_64-linux-gnu |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Indeed the patchelf stuff worked! Note that when you apt install python3-tk, you will get a _tkinter shared object library that is stripped of it's ELF section headers, and you cannot write an rpath into it. A warning has been added to GHA if it encounters this condition.
|
|
||
| # informative messaging | ||
| message("Setting up Python API, creating pyenergyplus package at ${EPLUS_EXE_DIR}/pyenergyplus") | ||
| message("PYTHON: Setting up API, creating pyenergyplus package at ${EPLUS_EXE_DIR}/pyenergyplus") |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I would like to move these to regular CMake messages instead of print statements.
|
|
||
| [Desktop Action VersionUpdater] | ||
| Name=Open IDF Version Updater | ||
| Exec=ENERGYPLUS_INSTALL_DIR/energyplus auxiliary updater |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
CLEAN little desktop file. :)
| "else echo 'Error: .desktop template file missing'; fi" | ||
| ], | ||
| "UNDOEXECUTE", | ||
| "rm", desktopFilePath |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Even added an uninstall step to clean up the .desktop file path.
| *Linux note*: if you try to launch the VersionUpdater program from the default files app, it | ||
| may launch in a text editor (since it is a shell script). Just right click and ask to "Run as a Program". | ||
|
|
||
| The classic version updater is included with this version on Windows and Mac, but will be removed in the future. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Users will find this file in the PreProcess folder if they go hunting for IDFVersionUpdater. This is just one vector that I'll be using to alert the users of these changes.
| install( | ||
| FILES ${PROJECT_SOURCE_DIR}/cmake/energyplus.desktop.in | ||
| DESTINATION share/applications | ||
| ) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I decided to leave these little shortcuts in. I honestly doubt many people will ever use them on Linux. Either they will be happy on a terminal and just execute ./energyplus auxiliary eplaunch, or they will use the desktop integration and click on the E+ icon on the dock. But it's fine for now.
| // Remove the executable name to get the directory | ||
| std::wstring directory(path); | ||
| size_t pos = directory.find_last_of(L"\\/"); | ||
| if (pos != std::wstring::npos) { | ||
| directory = directory.substr(0, pos); // Extract just the directory path | ||
| } | ||
|
|
||
| // Construct the target application path (assuming it's in the same directory) | ||
| std::wstring targetApp = directory + L"\\energyplus.exe"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Deferring this until later, but very happy to get this tested and integrated later.



Pull request overview
Allows launching the Python based version updater tool from the E+ CLI:
Screencast.from.2025-03-04.12-14-56.mp4
I'll kick off a test package so that any interested party could try it out. As of now I've only exercised the E+ CLI on Linux, but it works the same as the EP Launch CLI, which is happy on all platforms. Also, I had to make some improvements to the updater tool, and it's tested heavily across platforms itself, so I think it should be OK.....