Skip to content
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

Improve CMake build and port conversion tools to Linux #19

Merged
merged 31 commits into from
Aug 7, 2024

Conversation

Diomendius
Copy link

Firstly, thanks for your work on this port, Eric! I was pleased to discover John Calhoun had released Glider PRO's source and just as pleased to discover you had spent the effort to bring this piece of Macintosh history to modern systems.

This PR ports the house and resource conversion tools to Linux and improves the CMake build system to produce (and optionally install) a fully functional build of Aerofoil without the need to import the converted resources from the Windows build.

I've tried to do this in as portable a way as possible, and building on Mac may work without further modification, though I am unable to test this myself.

I've kept Windows-specific code untouched as best I can, but please let me know if I've somehow broken something in the Windows build.

Other notable changes

  • Enable Git line ending normalization for most text files
    Some files have CRLF endings, some files have LF endings, some files have mixed line endings. Letting Git normalize line endings internally will avoid whitespace-only merge conflicts in the future.
    • This will cause merge conflicts by default when merging branches based before this change. I'll keep my branch rebased against master, but if someone runs into conflicts, add -X renormalize to git merge or git rebase to resolve the issue automatically.
  • Fix double-use of va_list in gpr2gpa.cpp::AppendFmt()
    This one is actually a pretty major bug that the Windows version doesn't exhibit by sheer luck. On Linux, this causes the second call to vsnprintf() to print garbage, resulting in invalid JSON.
  • Fix = instead of == in gpr2gpa.cpp::DecompressSound()
    This typo means the following "unknown format" else-branch can never be hit, but I don't think it causes issues in practice when converting Glider PRO's resources. Still, no reason not to fix this.
  • Use / as path separator in a couple of the conversion tools
    Windows should have no problem with this whatsoever, but I'm making a note of this as I haven't tested Windows. If this does somehow break something, it will likely break it loudly, at least.
  • Avoid Clang c++11-narrowing error
    This is a warning by default in GCC, but a hard error in Clang, so I've added -Wno-error=c++11-narrowing when compiling with Clang. At some point, someone could fix the cause of this warning as a more permanent fix. I might submit another PR squashing some warnings in the future.
  • Update LINUX.txt with new and more detailed instructions

Related issues

@elasota
Copy link
Owner

elasota commented Aug 2, 2024

Thanks, I'll take a look at this over the weekend probably.

@elasota elasota self-requested a review August 2, 2024 21:25
Copy link
Owner

@elasota elasota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this mostly looks good but I'd have two main requests for now:

First, can you split the .gitattributes and line endings commits to a separate PR so this can be rebased on top of that? Having 839 file changes in the combined diff is making this difficult to review.

Second, I don't think UnixCompat.h should exist. The intent of the shim header (despite the name...) is to quarantine all of the MSVCRT problems in a way that the tools code doesn't need to worry about it, so a Unix port of it should just use a separate source file (and _fseeki64 and _ftelli64 should just have new wrapper funcs) and keep the same header.

sprintf_s doesn't need to be implemented, just change the source files to use sprintf instead, all of the tools using sprintf_s now are already including the Common property sheet that disables the VS "insecure CRT" warnings.

I guess fopen_s is still needed for now because bin2gp isn't using shim library, but bin2gp isn't needed for the package build. I can fix that afterwards so it can be taken out.

@elasota
Copy link
Owner

elasota commented Aug 2, 2024

Actually a correction on fopen_s: It's not necessary either for the same reason, the VS warnings that made it necessary are already disabled in bin2gp. Just use fopen instead.

It should be using fopen_utf8 like the other tools, but it looks like bin2gp wasn't properly updated to use the shim library like the other tools, so I will have to fix that so the VS build keeps working.

unpacktool/unpacktool.cpp Outdated Show resolved Hide resolved
gpr2gpa/gpr2gpa.cpp Outdated Show resolved Hide resolved
@Diomendius
Copy link
Author

It's possible to exclude whitespace changes in the GitHub UI, and to view individual commit diffs or shift-click select the range of commits excluding the normalization commit, but it's a lot clumsier than I realized it would be. GitHub also refuses to completely hide files with whitespace-only diffs, so you get 817 separate "Whitespace-only changes." messages, unlike the Git CLI. I'll split those commits into a separate PR. That will get rid of the big scary +324,613 −323,856 on this PR, too (even if it just moves it to the other PR).

  • sprintf_s() can actually be replaced with a string stream, which avoids having a fixed-size output buffer and the associated error case to handle.
  • I don't actually need to touch bin2gp.cpp as all the uses of fopen_s() are already gated behind #ifdef _CRT_INSECURE_DEPRECATE.
  • I think my reimplementations of ScanDirectoryForExtension() and MakeTimestamp should also work on Windows, so there's an opportunity to reduce code duplication in the future.

Here's your opportunity to bikeshed a better name than WindowsUnicodeToolShim/UnixUnicodeToolShim.cpp, by the way.

ts.SetMacEpochTime(currentTimeUnix + ts.kMacEpochToUTC);

ts.SetLocalYear(currentTimeStruct->tm_year + 1900);
ts.m_localMonth = currentTimeStruct->tm_mon;
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

kMacEpochToUTC should be subtracted from UTC time, not added. Also, local month needs to be +1 because it is months-since-January in struct tm

See GpSystemServices_POSIX::GetLocalDateTime

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, it's really stupid that tm_mon is 0-based but tm_mday is 1-based. I didn't have much of a reference for the correct format of your timestamp files, so thanks for catching this one for me.

I don't think you're right about the sign error, though. Assuming the Mac timestamp counts the number of seconds since 1904-01-01 00:00 UTC, which is the only sane interpretation I can think of,

2024-08-06 09:00 UTC
= 1722934800 seconds since 1970-01-01 00:00 UTC
= 3805779600 seconds since 1904-01-01 00:00 UTC

(1970-01-01 00:00 UTC) - (1904-01-01 00:00 UTC) = 2082844800
3805779600 = 1722934800 + 2082844800

Subtracting 2082844800 as per GpSystemServices_POSIX::GetTime():

1722934800 - 2082844800 = -359910000

(1904-01-01 00:00 UTC) + (-359910000) = 1892-08-04 09:00 UTC

That clearly isn't right, so it must be the other way.

Maybe kMacEpochToUTC isn't the best name for a magic number of 2082844800 but either it needs to stay positive and every instance of converting Unix → Mac should add this constant, and subtract for the reverse conversion, or the sign of kMacEpochToUTC needs to be flipped and every instance of converting Unix → Mac should subtract it, and add for the reverse.

If you intended the number to be the Mac epoch represented as a Unix timestamp, it should be a negative number.

@elasota
Copy link
Owner

elasota commented Aug 3, 2024

I think my reimplementations of ScanDirectoryForExtension() and MakeTimestamp should also work on Windows, so there's an opportunity to reduce code duplication in the future.

Unfortunately ScanDirectoryForExtension won't, opendir/readdir/etc. aren't available on Windows, and even if they were, they use char paths, which on Windows uses the system code page instead of UTF-8.

All file system calls in this use wchar_t on Windows so Unicode paths are properly supported.

CMakeLists.txt Outdated Show resolved Hide resolved
@elasota
Copy link
Owner

elasota commented Aug 3, 2024

OK, I looked through these as best I can and I think that should be all of the issues.

AppendFmt calls vsnprintf twice, first to check the size of the
formatted string, then to write it for real, but it used the same
va_list for both calls, so the second call got an invalid va_list after
the first call had already consumed all its arguments.

This is UB and at least on Linux makes the second call print garbage. I
presume Windows implements va_list differently such that this somehow
worked correctly, because on Linux, all of the dialog items get parsed
into invalid JSON due to this bug, with lines like this (note the
missing second array element and closing bracket):
    "pos" : [ -55947262,
The BUILD_INTERFACE generator expression isn't actually useful as we
don't use export(). CMAKE_CURRENT_SOURCE_DIR is also unnecessary as
CMake treats relative paths as relative to the current source directory
(or the current binary directory for outputs).
This is the counterpart to WindowsUnicodeToolShim.cpp for *nix systems.
Downgrades c++11-narrowing to a warning when compiling with Clang. A
better solution would be to fix the error, but this at least brings
Clang in line with the more permissive GCC, which treats this as a
warning by default.
I don't think this actually gets hit when converting the base Glider PRO
resources, but it's an obvious error that makes the condition always
true.
Also includes <algorithm> to provide std::find(). Evidently something in
Windows implicitly provides find(), but it was broken on Linux.
- Adds missing includes, removes some unused ones.
- Removes unused Windows.h and shellapi.h includes.
- Uses / as path separator. This is portable and should still work fine
  on Windows.
Also add stddef.h include to GpRenderedGlyphMetrics.h to make size_t
visible. Does MSVC provide size_t by default, or via stdint.h? This
prevents compilation and I can't see how this would have compiled on
Windows otherwise.
Removes unused Windows-specific headers and adds arguments to specify
source and output directories, which is necessary for out-of-tree
builds, which are necessary to avoid name collisions on platforms where
executables have no file extension (so, basically everything except
Windows).
- Includes WindowsUnicodeToolShim.h.
- Replaces sprintf_s() with std::ostringstream.
- Replaces fopen_s() with fopen_utf8().
- Switches to the toolMain() wrapper, which is a no-op on except on
  Windows, where it should improve Unicode support, though I can't test
  that on my end.
- Replaces \ with / in paths, which should still be Windows-compatible.
These are only used on Windows and the converted files have been
committed to the repo, but this might be useful to someone.
This automatically cleans up artifacts specified as BYPRODUCTS after
running the commands.
This is meant as an alias to the name of the main executable, for
consistency with the Executable install component.
All the individual executables are marked EXCLUDE_FROM_ALL, but the
added Tools custom target is marked ALL. The only visible effect of this
is that ConvertColorCursors does not get built by default, since all the
other tools are dependencies for the Resources or Tools targets, which
are both built by default. Otherwise, the benefit is simply to keep the
dependency tree clean. Only three targets are built by default:
Aerofoil, its resources and the conversion tools. Everything else is
built to satisfy dependencies.
Uses add_custom_command() to add rules for generating these directories,
rather than creating them only when CMakeLists.txt runs. With this
change, you can manually delete Packaged from the build directory
without causing subsequent builds to fail.
This will make CMake rebuild resources if for instance the fonts are
updated.
This allows intermediate build artifacts to be cleaned up without
specifying them individually as BYPRODUCTS.

When building a data file <name>, all files are first built under
tmp/<name> before the target itself is moved from tmp/<name>/<name> to
Packaged/<name>.

add_house_file() could also be modified in this way, but it wouldn't
reduce the boilerplate by much, so it's probably not worth it.
@Diomendius
Copy link
Author

Unfortunately ScanDirectoryForExtension won't, opendir/readdir/etc. aren't available on Windows, and even if they were, they use char paths, which on Windows uses the system code page instead of UTF-8.

I thought I saw opendir() in the Microsoft documentation, but that can't be right. I must have misremembered seeing something that is supported like fopen() and not gone back to check.

@Diomendius Diomendius requested a review from elasota August 6, 2024 09:48
Copy link
Owner

@elasota elasota left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should be okay now

@elasota elasota merged commit 4340e8f into elasota:master Aug 7, 2024
@elasota
Copy link
Owner

elasota commented Aug 7, 2024

Oh also please let me know if you want a credits line in the about box.

@Diomendius
Copy link
Author

Thanks for the merge!

Regarding the timestamps:

  • GpSystemServices_Win32::GetTime() is correct.
  • MakeTimestamp is correct on all platforms (the Windows code contains a duplicate of the correct code from GpSystemServices_Win32::GetTime()). I have tested that MakeTimestamp compiled on Linux from this PR branch and MakeTimestamp.exe from Aerofoil-1.1.2-win64-tools.zip produce identical timestamp files.
  • These all have sign errors:
    • ASADTool.cpp::ProcessFileDatesInfo()
    • GpSystemServices_Web::GetTime()
    • GpSystemServices_POSIX::GetTime()

Oh also please let me know if you want a credits line in the about box.

Sure, I have no objections to being mentioned.

This was referenced Aug 15, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants