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

RFC: Julia 1.7 support #496

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

RFC: Julia 1.7 support #496

wants to merge 11 commits into from

Conversation

Gnimuc
Copy link
Member

@Gnimuc Gnimuc commented Feb 17, 2022

As reworking Cxx.jl from the scratch takes more time than I thought, I'm going to try it again to upgrade the old code.
Thanks to https://github.com/JuliaLang/llvm-project, doing a source build is much easier than before.

  • Switch the build system to CMake (the C++ code is temporarily hosted here)
  • libcxxffi
    • Upgrade libcxxffi to LLVM 12
    • Find the reason why cleanup_cpp_env segfaults
    • Implement exception-handing for Windows (x-ref) (pending)
    • Fix the “Duplicate definition of symbol” issue by force-applying linkage
      • private GVs
      • global GVs (needs help)
  • Cxx.jl
    • Regenerate clang_constants.jl
    • Refactor initialization.jl(use ClangCompiler.jl's JLLEnvs module for shipping system headers)
    • Adapt llvmcall to Julia 1.7
    • Rework IR generation on top of LLVM.jl
  • Find the reason why modules can not be correctly merged.
  • Broken tests:
    • cxxstr.jl: 103
    • icxxstr.jl: inlineexpr, 103
    • misc.jl
      • 53
      • 55
      • booleans as template arguments
      • Members with non-trivial copy constructor
      • Memory management
      • 141
      • Implement C++ Functions in julia
      • fooTheLambda
      • 217
      • 243
      • 303

As we don't support the old src-build anymore, there is no need to keep the C++ source code in this repo.

`bootstrap.cpp` is moved to a new repo called `libcxxffi`.
@oschulz
Copy link
Contributor

oschulz commented Feb 17, 2022

Thanks for this @Gnimuc , having Cxx back will be awesome!

`setup_instance` is reworked to use `clang::createInvocationFromCommandLine` for setting compilation arguments. This makes it easier for users to get full control of language features like `RTTI`. System headers can also be configured via common `-isystem` flags.
@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Feb 25, 2022

I'm going to try it again to upgrade the old code.

Great!
Is this a temporary solution, i.e. likely to break again in 1.8 (that seems real close), or later Julia version (or strictly speaking major LLVM version upgrades, which I think was the problem)? I'm not up-to-speed on the reimplementation, or this update, but am curious why target 1.7, not 1.6? That's good enough for me, and I guess many others, or even 1.8 if it helps. Well I'm not a Cxx user, I just like this package, and would promote it (again) if I think it's not likely to break again.

Feel free to close/"won't fix" #487 (unless you later plan to backport to 1.6) that I opened (and Spot.jl mentioned there, already moved to CxxWrap.jl), and I suppose all other issues on 1.4, 1.5...

@Gnimuc
Copy link
Member Author

Gnimuc commented Feb 26, 2022

Is this a temporary solution, i.e. likely to break again in 1.8 (that seems real close), or later Julia version (or strictly speaking major LLVM version upgrades, which I think was the problem)?

I'm sure it will break again in 1.8, but it should be easier to upgrade. The main problem here is that Cxx.jl uses some Julia internal functions(e.g. jl_get_llvmf_decl) which were removed between Julia 1.4~1.5, so the corresponding Cxx features (e.g. interpolating a Julia function call expr in icxx_str macro) need to be adapted accordingly.

There is no intention to resurrect all of the cool features of Cxx.jl in this PR, I just want to see how far it goes and what Julia internal functions we need, so we can open feature requests in the Julia upstream to add new stable APIs for us.

I'm not up-to-speed on the reimplementation, or this update, but am curious why target 1.7, not 1.6?

For the reimplementation, I'd like to use the newly introduced incremental compiling feature in LLVM 13, but that will need Julia 1.8. For this upgrade, we don't have the patched source code of LLVM/Clang for Julia 1.6 at this moment(we will never have that if no one would like/has time to contribute).

@oschulz
Copy link
Contributor

oschulz commented Feb 26, 2022

I like your plan, @Gnimuc - again, thanks for trying to resurrect Cxx!

@Gnimuc Gnimuc mentioned this pull request Mar 11, 2022
this should be rebased in the future.
@Gnimuc
Copy link
Member Author

Gnimuc commented Mar 30, 2022

Now, I can get the following examples to work. Unfortunately, due to some changes in Julia's JIT, it's not easy to resurrect the magic "insert Julia functions into the C++ code" feature(e.g. Example 4 in the README). Any feedback on what features are used in your old Cxx.jl-based projects?

# runs on macOS with Julia 1.7.2
julia> using Cxx

julia> cxx""" #include<iostream> """
true

julia> cxx"""  
         void mycppfunction() {   
            int z = 0;
            int y = 5;
            int x = 10;
            z = x*y + 2;
            std::cout << "The number is " << z << std::endl;
         }
       """
true

julia> julia_function() = @cxx mycppfunction()
julia_function (generic function with 1 method)

julia> julia_function()
In file included from /Cxx.h:1:
/Users/gnimuc/.julia/dev/Cxx/src/std.jl:112:38: warning: expression result unused
std::vector<bool> &vr = __juliavar1; vr;
                                     ^~
/Users/gnimuc/.julia/dev/Cxx/src/std.jl:43:12: error: implicit instantiation of undefined template 'std::vector<bool>'
__juliavar1.size();
           ^
/Users/gnimuc/.julia/artifacts/8571aac530057acc3f32ffab9003dc3e00b24723/x86_64-apple-darwin14/sys-root/usr/include/c++/v1/iosfwd:217:28: note: template is declared here
class _LIBCPP_TEMPLATE_VIS vector;
                           ^
In file included from /Cxx.h:1:
/Users/gnimuc/.julia/dev/Cxx/src/std.jl:112:38: warning: expression result unused
std::vector<bool> &vr = __juliavar1; vr;
                                     ^~
The number is 52

julia> jnum = 10
10

julia> cxx"""
           void printme(int x) {
              std::cout << x << std::endl;
           }
       """
true

julia> @cxx printme(jnum)
10

julia> cxx"""
         void printme(const char *name) {
            // const char* => std::string
            std::string sname = name;
            // print it out
            std::cout << sname << std::endl;
         }
            """
true

julia> @cxx printme(pointer("John"))
John

julia> cxx"""
       class Klassy {
           public:
               enum Foo { Bar, Baz };
               static Foo exec(Foo x) { return x; }
       };
       """
true

julia> @cxx Klassy::Bar
Cxx.CxxCore.CppEnum{Symbol("Klassy::Foo"), UInt32}(0x00000000)

julia> @cxx Klassy::exec(@cxx(Klassy::Baz))
Cxx.CxxCore.CppEnum{Symbol("Klassy::Foo"), UInt32}(0x00000001)

julia> cxx"""#include <iostream>
       class Hello
       {
           public:
               void hello_world(const char *now){
                   std::string snow = now;
                   std::cout << "Hello World! Now is " << snow << std::endl;
               }
        };"""
true

julia> hello_class = @cxxnew Hello()
(class Hello *) @0x00006000013d5040

julia> using Dates

julia> tstamp = string(Dates.now())
"2022-03-31T01:01:02.900"

julia> @cxx hello_class -> hello_world(pointer(tstamp))
Hello World! Now is 2022-03-31T01:01:02.900

@Gnimuc
Copy link
Member Author

Gnimuc commented Mar 30, 2022

For those contributors who would like to get involved in the development of this package, this PR is probably a good starting point. To test this PR, you need to 1. build https://github.com/Gnimuc/libcxxffi and make install; 2. add export LIBCXXFFI_INSTALL_PREFIX=/Users/your/path/to/libcxxffi/build/install to your .bashrc; 3. dev Cxx.jl (you may also need to install https://github.com/Gnimuc/LLVMCGUtils.jl).

@Gnimuc Gnimuc changed the title WIP: Julia 1.7 support RFC: Julia 1.7 support Mar 31, 2022
@Gnimuc Gnimuc marked this pull request as ready for review March 31, 2022 00:42
@ShoofLLC
Copy link

ShoofLLC commented Apr 2, 2022

EDIT: NVM just noticed a submodule :/

@sliwowitz
Copy link

We've built & installed libcxxffi, exported the path, added LLVMCGUtils.jl, and tried to build Cxx.jl using Pkg.add(url="https://github.com/JuliaInterop/Cxx.jl.git", rev="fix-julia-1.7"), but we've got an error collectAllHeaders not defined (the function definition has been removed from initialization.jl in this PR)

julia> using Cxx
[ Info: Precompiling Cxx [a0b5b9ef-44b7-5148-a2d1-f6db19f3c3d2]
ERROR: LoadError: UndefVarError: collectAllHeaders not defined
Stacktrace:
 [1] top-level scope
   @ ~/.julia/packages/Cxx/cr4BV/src/initialization.jl:232
 [2] include(x::String)
   @ Cxx.CxxCore ~/.julia/packages/Cxx/cr4BV/src/Cxx.jl:143
 [3] top-level scope
   @ ~/.julia/packages/Cxx/cr4BV/src/Cxx.jl:173
 [4] top-level scope (repeats 2 times)
   @ none:1
in expression starting at /home/strazce/.julia/packages/Cxx/cr4BV/src/initialization.jl:232
in expression starting at /home/strazce/.julia/packages/Cxx/cr4BV/src/Cxx.jl:141
ERROR: Failed to precompile Cxx [a0b5b9ef-44b7-5148-a2d1-f6db19f3c3d2] to /home/strazce/.julia/compiled/v1.7/Cxx/jl_w17t2p.

@melonedo
Copy link

melonedo commented Oct 2, 2022

I had a quick test on linux. It managed to compile C++ code, but crashes when the llvmcall is compiled. I can not procede any further so I leave a quick note here in case someone has time.

but we've got an error collectAllHeaders not defined

@melonedo
Copy link

melonedo commented Oct 4, 2022

Now I am stuck again. It is forbidden to call eval inside a generated function, so we need to find another way to call the constructors.

@Gnimuc have you come across similar issues about constructors? It seems that related functions (RunGlobalConstructors) are commented out.

@Gnimuc
Copy link
Member Author

Gnimuc commented Oct 4, 2022 via email

@melonedo
Copy link

melonedo commented Oct 4, 2022

I am sorry but I can not find RunGlobalConstructors in https://github.com/Gnimuc/LLVMCGUtils.jl, can you provide more information?

@Gnimuc
Copy link
Member Author

Gnimuc commented Oct 5, 2022

I am sorry but I can not find RunGlobalConstructors in https://github.com/Gnimuc/LLVMCGUtils.jl, can you provide more information?

Sorry, I was using a phone last night and didn't check the code. What I meant is that the CollectGlobalConstructors is implemented in LLVMCGUtils.jl.

@Gnimuc have you come across similar issues about constructors? It seems that related functions (RunGlobalConstructors) are commented out.

Indeed. RunGlobalConstructors are commented out in this PR. But I forget why I did that. 😰 The reason could be either I mistakenly did that to debug something or calling those global constructors manually is no longer necessary(I doubt this is valid though). Did you run into any problems related to global ctors?

To call CollectGlobalConstructors, we could use LLVM.jl's call_function rather than eval.

@melonedo
Copy link

melonedo commented Oct 5, 2022

Indeed. RunGlobalConstructors are commented out in this PR. But I forget why I did that. 😰

I guess it is because its signature changed. It accepts an LLVM.Module, but a CxxInstance is passed.
It seems that the constructor issue is because I only tested the llvmcall alone, running it as @cxx mycppfunction seems to be fine.

Now mycppfunction can be compiled and run, but printme fails because of "Duplicate definition of symbol std::__ioinit".

@Gnimuc
Copy link
Member Author

Gnimuc commented Oct 5, 2022

"Duplicate definition of symbol std::__ioinit"

This is exactly where I got stuck.

@PallHaraldsson
Copy link
Contributor

PallHaraldsson commented Jun 21, 2024

I guess there's no need to target 1.7 by now. Would it be easier to target just current stable Julia and its LLVM or possibly only Julia 1.11/1.12 and latest LLVM 18.1.7? I see "memory management" under broken tests. Does the new Julia Memory type help to get Cxx.jl working again, or the opposite since written in pure Julia, and before in C? Is it realistic this project will work again, and not break or would that always be a possibility, with e.g. changes in LLVM? And with full platform support, or even only adding for Windows, unclear to me how bad it was or its issues.

@melonedo
Copy link

melonedo commented Jun 22, 2024 via email

@Gnimuc
Copy link
Member Author

Gnimuc commented Jun 22, 2024

I guess there's no need to target 1.7 by now. Would it be easier to target just current stable Julia and its LLVM or possibly only Julia 1.11/1.12 and latest LLVM 18.1.7? I see "memory management" under broken tests. Does the new Julia Memory type help to get Cxx.jl working again, or the opposite since written in pure Julia, and before in C? Is it realistic this project will work again, and not break or would that always be a possibility, with e.g. changes in LLVM? And with full platform support, or even only adding for Windows, unclear to me how bad it was or its issues.

for an alternative solution, see https://github.com/Gnimuc/CppInterOp.jl

@oschulz
Copy link
Contributor

oschulz commented Jun 22, 2024

@Gnimuc how does CppInterOp.jl work under the hood, compared to Cxx.jl?

@Gnimuc
Copy link
Member Author

Gnimuc commented Jun 23, 2024

@Gnimuc how does CppInterOp.jl work under the hood, compared to Cxx.jl?

CppInterOp is a C++ interpreter, allowing us to create packages similar to PyCall and RCall. OTOH, Cxx.jl operates at the LLVM IR level. Clang is used to generate LLVM IR, which is then tweaked and sent into Julia's pipeline for execution. The Julia internals are not stable, that's why we stuck at 1.3.

A workaround is to use GPUCompiler to build our own pipeline. Those GPUCompiler-based packages are very good examples.(e.g. Enzyme.jl)

@oschulz
Copy link
Contributor

oschulz commented Jun 23, 2024

CppInterOp is a C++ interpreter

Does it use parts of Clang for that, or is it a standalone interpreter?

@Gnimuc
Copy link
Member Author

Gnimuc commented Jun 23, 2024

CppInterOp is a C++ interpreter

Does it use parts of Clang for that, or is it a standalone interpreter?

It originates from cling maintained by cling devs and hasn't been fully upstreaming to LLVM yet, see https://compiler-research.org/libinterop/ for the original proposal, which was published 2 years ago.

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.

6 participants