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

Some effort to compile on windows #7

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

Kreijstal
Copy link

This is some effort, complete compilation fails due to perl shenanigans and because I have no idea how perl works, but at least the example.c is compiled.

image

Copy link
Member

@Minoru Minoru left a comment

Choose a reason for hiding this comment

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

This is pretty cool, but I have to wonder why you're even working on this :) STFL is an extremely niche library. To my knowledge (backed by apt-cache rdepends libstfl0), it's only used by Newsboat, but we plan to move away from it (newsboat/newsboat#232).

I'll merge this once the iconv thing is fixed, and I'm not dissuading you from further working on this; just want to know your motivation.

Makefile Outdated Show resolved Hide resolved
@Minoru
Copy link
Member

Minoru commented Dec 28, 2023

Also, what Perl issues did you run into? Perhaps I'd be able to help.

@Kreijstal
Copy link
Author

Also, what Perl issues did you run into? Perhaps I'd be able to help.

I guess mainly telling windows perl that using bash.exe is okay
check this out

export PERL5SHELL="bash -l -c"
kreij@LAPTOP-31E3HV7R MINGW64 ~/stfl
$ make clean
gcc -pthread -I. -MM *.c > Makefile.deps_new
gcc -pthread -I. -MM widgets/*.c | sed 's,^wt_[^ ]*\.o: ,widgets/&,' >> Makefile.deps_new
mv -f Makefile.deps_new Makefile.deps
rm -f libstfl.a example core core.* *.o Makefile.deps
rm -f widgets/*.o spl/mod_stfl.so spl/example.db
cd perl5 && perl Makefile.PL && make clean && rm -f Makefile.old
mingw32-make[1]: *** No rule to make target 'C:\Users\kreij\scoop\apps\msys2\2022-01-28\mingw64\lib\perl5\core_perlConfig.pm', needed by 'Makefile'.  Stop.
mingw32-make[1]: *** No rule to make target 'C:\Users\kreij\scoop\apps\msys2\2022-01-28\mingw64\lib\perl5\core_perlConfig.pm', needed by 'Makefile'.  Stop.
mingw32-make[1]: *** No rule to make target 'C:\Users\kreij\scoop\apps\msys2\2022-01-28\mingw64\lib\perl5\core_perlConfig.pm', needed by 'Makefile'.  Stop.
Generating a make-style Makefile
Writing Makefile for stfl
Writing MYMETA.yml and MYMETA.json
make[1]: Entering directory '/home/kreij/stfl/perl5'
make[1]: *** No rule to make target 'C:\Users\kreij\scoop\apps\msys2\2022-01-28\mingw64\lib\perl5\core_perlConfig.pm', needed by 'Makefile'.  Stop.
make[1]: Leaving directory '/home/kreij/stfl/perl5'
make: *** [Makefile:73: clean] Error 2

I assume the file that it wants it's 'C:\Users\kreij\scoop\apps\msys2\2022-01-28\mingw64\lib\perl5\core_perl\Config.pm' but because of path conversion shenanigans it's hard to see :(, as for the reason for doing this, it's because it was a dependency of newsboat, and wanted to compile it for windows, and yeah, I'm excited about the new tool/library that is going to replace sftl

@Minoru
Copy link
Member

Minoru commented Dec 28, 2023

it's because it was a dependency of newsboat, and wanted to compile it for windows

Wow! Okay, let's work on this then :)

The output here on Debian stable looks somewhat differently:

$ make clean
rm -f libstfl.a example core core.* *.o Makefile.deps
rm -f widgets/*.o spl/mod_stfl.so spl/example.db
cd perl5 && perl Makefile.PL && make clean && rm -f Makefile.old
Generating a Unix-style Makefile
Writing Makefile for stfl
Writing MYMETA.yml and MYMETA.json
make[1]: Entering directory '/dev/shm/stfl/perl5'
rm -f \
  stfl.bso stfl.def \
  stfl.exp stfl.x \
  stfl.bs blib/arch/auto/stfl/extralibs.all \
  blib/arch/auto/stfl/extralibs.ld Makefile.aperl \
  *.a *.o \
  *perl.core MYMETA.json \
  MYMETA.yml blibdirs.ts \
  core core.*perl.*.? \
  core.[0-9] core.[0-9][0-9] \
  core.[0-9][0-9][0-9] core.[0-9][0-9][0-9][0-9] \
  core.[0-9][0-9][0-9][0-9][0-9] libstfl.def \
  mon.out perl \
  perl perl.exe \
  perlmain.c pm_to_blib \
  pm_to_blib.ts so_locations \
  tmon.out
rm -rf \
  blib
mv Makefile Makefile.old > /dev/null 2>&1
make[1]: Leaving directory '/dev/shm/stfl/perl5'
rm -f perl5/stfl_wrap.c perl5/stfl.pm perl5/build_ok
rm -f python/stfl.py python/stfl.pyc python/_stfl.so
rm -f python/stfl_wrap.c python/stfl_wrap.o
rm -f ruby/Makefile ruby/stfl_wrap.c ruby/stfl_wrap.o
rm -f ruby/stfl.so ruby/build_ok Makefile.deps_new
rm -f stfl.pc libstfl.so libstfl.so.*

I can run the Perl script manually and examine the Makefile:

$ cd perl5
$ perl Makefile.PL

In it, I see this line:

CONFIGDEP = $(PERL_ARCHLIBDEP)$(DFSEP)Config.pm $(PERL_INCDEP)$(DFSEP)config.h

Something's up with DFSEP then? The definitons are towards the beginning of the file:

DFSEP = $(DIRFILESEP)

and finally:

DIRFILESEP = /

So apparently the Perl module ExtUtils::MakeMaker doesn't support Windows. Quick websearch led me to https://stackoverflow.com/a/9455881/2350060, which claims that (back in 2012 at least) this module didn't support GNU Make (not by design, rather by coincidence), although the error message in that question was quite different. I think you'd have to delve deeper into that Perl module's issue tracker to find out how things stand today.

This is on Linux. On Windows, you might be running into ramifications of this one: https://stackoverflow.com/a/9455881/2350060 You're getting a different error, it looks like for you DIRFILESEP is just empty. Can you double-check that?

However, if we take a step back and re-examine the situation, then maybe you did enough already. Newsboat doesn't use Perl bindings to STFL. All it needs is libstf.so library and stfl.h header. You got that building already, so mission accomplished I guess?

(Edited once I realized that of course for me the separator is a slash -- I'm on Linux!)

@Kreijstal
Copy link
Author

Kreijstal commented Dec 28, 2023

my DIRFILESEP is \ which makes sense, but is there a way to change it to / considering I am on bash on windows, but it looks like MakeMaker is unmantained :D (or more or less there are other tools for perl), anyway, you've been very helpful, thank you so much. And yeah I don't think anyone is looking to use sftl.. with perl... on windows.

VERSION := 0.24
ifeq ($(detected_OS),Windows)
SHARED_LIB_NAME := libstfl.$(VERSION).$(SHARED_LIB_EXT)
Copy link
Member

Choose a reason for hiding this comment

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

SHARED_LIB_EXT is only used here. How about hard-coding it to dll here and removing the variable?

Comment on lines +95 to +100
install -m 644 libstfl.$(VERSION).dll $(DESTDIR)$(prefix)/$(libdir)
cp $(DESTDIR)$(prefix)/$(libdir)/libstfl.$(VERSION).dll $(DESTDIR)$(prefix)/$(libdir)/libstfl.dll
else
install -m 644 libstfl.so.$(VERSION) $(DESTDIR)$(prefix)/$(libdir)
ln -fs libstfl.so.$(VERSION) $(DESTDIR)$(prefix)/$(libdir)/libstfl.so

endif
Copy link
Member

Choose a reason for hiding this comment

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

I think it'd be a good idea to use SHARED_LIB_NAME here, and also check if there's other places where it can be used. That way, we confine the knowledge to a single variable, and it'd be harder to accidentally break the build in the future by hard-coding a specific name.

Comment on lines +47 to +49
wchar_t codePageStr[10];
swprintf(codePageStr, 10, L"%u", codePage);
ipool = stfl_ipool_create(codePageStr);
Copy link
Member

Choose a reason for hiding this comment

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

After looking at this again, I wonder how it even compiles. Here, we're passing wchar_t* into stfl_ipool_create() which expects char* — why isn't it a compilation error to do so?

Assuming wchar_t* simply gets casted to char* somehow, this code is broken: wchar_t for a digit would contain zeroes (digits are part of ASCII, many encodings are extensions of ASCII, including all of Unicode encodings). Thus stfl_ipool_create() will only use the first digit of the codepage, if even that (zeroes might be at the very start of the string).

Here's a test program to verify that a string can be converted from UTF-8 to WCHAR_T and then to UTF-32:

#include <iconv.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <wchar.h>

// "Hello" in Ukrainian, in UTF-8
char INPUT[] = {
    0xd0, 0x9f, 0xd1, 0x80, 0xd0, 0xb8, 0xd0, 0xb2, 0xd1, 0x96, 0xd1, 0x82, 0x0 };
// Same string in UTF-32
char EXPECTED_UTF32_OUTPUT[] = {
    0xff, 0xfe, 0x00, 0x00, 0x1f, 0x04, 0x00, 0x00, 0x40, 0x04, 0x00, 0x00, 0x38, 0x04,
    0x00, 0x00, 0x32, 0x04, 0x00, 0x00, 0x56, 0x04, 0x00, 0x00, 0x42, 0x04, 0x00, 0x00
};

int main() {
    const char input_code[] = "UTF-8";
    iconv_t conv = iconv_open("WCHAR_T", input_code);
    if(conv == (iconv_t)-1) {
        perror("opening iconv for conversion from UTF-8 to WCHAR_T failed");
        exit(1);
    }

    char* input = INPUT;
    char* input_ptr = input;
    size_t inputbytesleft = strlen(input_ptr);

    const size_t OUT_BUFFER_SIZE = 4096; // should be enough for any encoding under the Sun
    char* wc_string = malloc(OUT_BUFFER_SIZE);
    if(wc_string == NULL) {
        perror("allocating a buffer for the wide string failed");
        exit(1);
    }

    char* output_ptr = wc_string;
    size_t outbytesleft = OUT_BUFFER_SIZE;

    size_t chars_converted =
        iconv(
            conv,
            &input_ptr,
            &inputbytesleft,
            &output_ptr,
            &outbytesleft);
    if(chars_converted == (size_t)-1) {
        free(wc_string);
        perror("conversion from UTF-8 to WCHAR_T failed");
        exit(1);
    }

    if(wcslen((wchar_t*)wc_string) == 0) {
        free(wc_string);
        printf("Expected WCHAR_T string to contain some bytes, but it is empty\n");
        exit(1);
    }

    if(iconv_close(conv) == -1) {
        free(wc_string);
        perror("closing iconv for conversion from UTF-8 to WCHAR_T failed");
        exit(1);
    }

    const char output_code[] = "UTF-32";
    conv = iconv_open(output_code, "WCHAR_T");
    if(conv == (iconv_t)-1) {
        free(wc_string);
        perror("opening iconv for conversion from WCHAR_T to UTF-32 failed");
        exit(1);
    }

    input_ptr = wc_string;
    inputbytesleft = OUT_BUFFER_SIZE - outbytesleft;

    char* utf32_string = malloc(OUT_BUFFER_SIZE);
    if(utf32_string == NULL) {
        free(wc_string);
        perror("allocating a buffer for the UTF-32 string failed");
        exit(1);
    }

    output_ptr = utf32_string;
    outbytesleft = OUT_BUFFER_SIZE;

    chars_converted =
        iconv(
            conv,
            &input_ptr,
            &inputbytesleft,
            &output_ptr,
            &outbytesleft);
    if(chars_converted == (size_t)-1) {
        free(utf32_string);
        free(wc_string);
        perror("conversion from WCHAR_T to UTF-32 failed");
        exit(1);
    }

    if(iconv_close(conv) == -1) {
        free(utf32_string);
        free(wc_string);
        perror("closing iconv for conversion from WCHAR_T to UTF-32 failed");
        exit(1);
    }

    const size_t utf32_string_len = OUT_BUFFER_SIZE - outbytesleft;
    const size_t EXPECTED_UTF32_STRING_LEN = 28;
    if(utf32_string_len != EXPECTED_UTF32_STRING_LEN) {
        printf("Expected UTF-32 string to contain %lu bytes, but it contains %lu\n",
                EXPECTED_UTF32_STRING_LEN,
                utf32_string_len);
        free(utf32_string);
        free(wc_string);
        exit(1);
    }

    for(size_t i = 0; i < EXPECTED_UTF32_STRING_LEN; ++i) {
        if(utf32_string[i] != EXPECTED_UTF32_OUTPUT[i]) {
            printf("UTF-32 output differs from expected at position %lu: expected %u, found %u\n",
                    i,
                    EXPECTED_UTF32_OUTPUT[i],
                    utf32_string[i]);
        }
    }

    free(utf32_string);
    free(wc_string);
}

Can you please modify it to run on Windows? In the process you'll figure out all the kinks of how to initialize iconv, and then you can just copy that code here.

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