# How about hosting C/C++/Fortran/Rust code in Julia packages?

**URL:** https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962
**Category:** Package Management
**Created:** [August 18, 2023, 6:39pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962 "2023-08-18T18:39:24Z")
**Posts on this page:** 14
**Page:** 1

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 18, 2023, 6:39pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/1 "2023-08-18T18:39:24Z")

</div>

Hey guys,

Many of you already knows me as a great Julia follower/developer/advocate in many platforms. So what I mention here is not criticizing Julia’s way of managing legacy or foreign code but my goal is to shed light on it if there are possible new developments.

I started to use R when I was a PhD. student in 2005. Then in many years, I adopted my C and C++ code in a hard way. After using the Rcpp package, calling into C and C++ binaries were as easy as calling R citizen counterparts.

In Julia, I can not see the same straightforward approach when it comes to talking to strangers. Here is my first attempt to migrate an R package’s Fortran part to Julia and what I got is total fail.

> <https://github.com/JuliaPackaging/Yggdrasil/issues/7224>
>
> Hey guys,
> 
> I hope this issue helps with the migration of some legacy code to J…ulia and also paves the way for the addition of similar packages in the future.
> 
> The issue is about migrating the Fortran part of an R package, namely mrfDepth, which is hosted as an R package in \[mrfDepth\](https://github.com/cran/mrfDepth).
> 
> The main interest is the \`rdepthmedian\` function which is used for estimating the Deepest Regression parameters, a well known robust regression estimator. It is simply used like 
> 
> \`\`\`R
> R\> rdepthmedian(maxit = 10000, x = stackloss)
> $deepest
> intercept slope var. 1 slope var. 2 slope var. 3 
> \-35.37610619 0.82522124 0.44247788 -0.07964602 
> \`\`\`
> 
> where the first parameter is intercept and the remaining part represents the partial slops. 
> 
> When I compile all of the fortran code in a single binary using 
> 
> \`\`\`shell
> $ gfortran -shared -fPIC \*.f
> \`\`\`
> 
> I can bring all of the functionality into Julia using the FFI features. The estimated parameters can be re-calculated in Julia using 
> 
> \`\`\`Julia
> X = convert(Matrix, stackloss) 
> n, p = size(X)
> n = Int32(n)
> p = Int32(p)
> A = zeros(Float64, p)
> maxit = Int32(10000)
> iter = Int32(1)
> MDEPAPPR = Int32(3)
> result = ccall((:sweepmedres\_, "./a.out"), 
> Cint, 
> (Ref{Float64}, # X
> Ref{Int32}, # n
> Ref{Int32}, # np
> Ref{Float64}, # A
> Ref{Cint}, # maxit 
> Ref{Cint}, # iter
> Ref{Cint} # MDEPAPPR
> ), X, n, p, A, maxit, iter, MDEPAPPR)
> 
> println(A)
> \`\`\`
> 
> and the codes returns the same estimates as we obtained using R:
> 
> \`\`\`julia
> \[0.8252212389746946, 0.44247787604338223, -0.0796460177080886, -35.37610619462\] 
> \`\`\`
> 
> where the last term is intercept and first 3 estimates are partial slopes. 
> 
> The problem is, the package is an R package and I failed to make it done using BinaryBuilder.jl. 
> 
> \- Can any talented friends in this area help migrating this functionality into Julia?
> \- Can we standardize the toolchain that inputs an R package and prepare a jdll output in an easy way?
> 
> Sorry if I am bothering you for a specific issue. 
> 
> Thank you for considering my message.

Using the C/C++/Fortran compiler manually and generating a shared library is not a problem for us Julians. By using the FFI feature, it is also easy to call into binary functions. But I think creating a yggdrasil pull request is not that easy.

Please change my mind, if I am getting it wrong.

In R, the packaging system always interacts with the local C/C++/Fortran compiler, generates the binaries and gets everything done for the end-user. In Windows and Mac systems pre-compiled binaries are served in a way similar to Julia’s one. But the source code is hosted in a single package. A package developer can write/test his both R and C code in the same development stage. A single

R CMD build/test/install

makes everything ready.

Can we borrow same functionality from R? What do you think?

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [August 18, 2023, 6:48pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/2 "2023-08-18T18:48:41Z")

</div>

> [@jbytecode](#):
>
> In R, the packaging system always interacts with the local C/C++/Fortran compiler, generates the binaries and gets everything done for the end-user.

In fact, Julia used to do that (typically with [BinDeps.jl](https://github.com/JuliaPackaging/BinDeps.jl)). And you can still do that if you want (either via BinDeps.jl or manually in your deps/build.jl script). But it’s pretty fragile — there are just so many ways for people’s local build systems to be broken or idiosyncratic, and debugging user problems was a huge pain. The [BinaryBuilder.jl](https://github.com/JuliaPackaging/BinaryBuilder.jl) style of cross-compiled prebuilt binaries (e.g. via Yggdrasil), in comparison, has been relatively painless and I think most of us found it to be a huge improvement … for users, it almost always just works, and for developers you only need to get a build script working once and then forget about it. But cross-compiling is a bit of a different art than usual software builds, so on the developer side it takes a bit of getting used to.

---

<div class="post-metadata">

### Author: ![dylanxyz](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/dylanxyz/32/36646_2.png) [@dylanxyz](https://discourse.julialang.org/u/dylanxyz)
#### Post date: [August 18, 2023, 7:26pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/3 "2023-08-18T19:26:11Z")

</div>

BinaryBuilder also allows you to build the JLL package locally so you can test on your platform before making a pull request to Yggdrasil, then you can `pkg> dev` the JLL to work with in other packages locally.

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [August 18, 2023, 7:51pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/4 "2023-08-18T19:51:38Z")

</div>

Using the `run_wizard()` function from BinaryBuilder is actually easy, if you have a reasonable Makefile (particularly if you have a cmake one). The hard part is to convince Mosè that your build script is not an insane mess (which in my case always is). But when you pass over Mosè’s bar, you’ll probably have a very solid build for all platforms, something that I was never able to do with my standard packages that are written in other languages. At the end I currently I’m just writing simple parsers for all my other-language packages in Julia, and they are much easier to distribute that way.

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 18, 2023, 7:56pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/5 "2023-08-18T19:56:36Z")

</div>

Thank you for the response. Did you have a chance to take a look at the link I provided in the first entry (a github issue about migrating R package to Julia).

---

<div class="post-metadata">

### Author: ![lmiq](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/lmiq/32/18314_2.png) [@lmiq](https://discourse.julialang.org/u/lmiq)
#### Post date: [August 18, 2023, 8:10pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/6 "2023-08-18T20:10:17Z")

</div>

I did now, briefly.

First, I opened the site of the package and didn’t immediately find a fortran code there, so it is not clear to me exactly what are you compiling with the command you provide there. But that is probably easy to clarify.

If you provide somewhere detailed instructions on how to download and compile the package in _one_ machine, it will be fairly easy to create a build script for the BinaryBuilder wizard.

You will basically need a script with more or less this content, which is created by the wizard (and here already adjusted by the tips of Mosè):

[example of simple build script for fortran program](https://github.com/JuliaPackaging/Yggdrasil/blob/master/M/MDLovoFit/build_tarballs.jl)

where a simple example Makefile can be like this: [https://github.com/m3g/MDLovoFit/blob/main/CMakeLists.txt](https://github.com/m3g/MDLovoFit/blob/main/CMakeLists.txt)

All that working (I did all this for the first time a couple of weeks ago, by the way), you will create a Julia package to provide the interface for that function. Since you know already how to call the function you want from Julia, you just need a package that exports a function with that enclosed, given the user inputs.

There might be some differences if your package provides a library, not an executable, etc, and yes, building these can be cumbersome at first, but when done you’ll have a very robust distribution.

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 18, 2023, 8:23pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/7 "2023-08-18T20:23:20Z")

</div>

Sorry, I misspelled the package name. I updated the issue title, content and the first entry.  
The source repository is

> **[GitHub - cran/mrfDepth:...](https://github.com/cran/mrfDepth)**
>
> :exclamation: This is a read-only mirror of the CRAN R package repository. ...

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 18, 2023, 8:32pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/8 "2023-08-18T20:32:04Z")

</div>

and, the links you provided seem to be very helpful. I will take a shot whenever I have get a time. thank you!

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [August 19, 2023, 1:18am UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/9 "2023-08-19T01:18:20Z")

</div>

I recommend joining the the #binarybuilder channel on Slack for interactive assistance.

The [https://binarybuilder.org/](https://binarybuilder.org/) is much less demanding and dependent on the user’s environment and delivers a much more consistent cross platform experience for users.

[https://docs.binarybuilder.org/stable/](https://docs.binarybuilder.org/stable/)

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [August 21, 2023, 12:30am UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/10 "2023-08-21T00:30:43Z")

</div>

I have a draft recipe here:

> <https://github.com/JuliaPackaging/Yggdrasil/issues/7224#issuecomment-1685440923>
>
> Hey guys,
> 
> I hope this issue helps with the migration of some legacy code to J…ulia and also paves the way for the addition of similar packages in the future.
> 
> The issue is about migrating the Fortran part of an R package, namely mrfDepth, which is hosted as an R package in \[mrfDepth\](https://github.com/cran/mrfDepth).
> 
> The main interest is the \`rdepthmedian\` function which is used for estimating the Deepest Regression parameters, a well known robust regression estimator. It is simply used like 
> 
> \`\`\`R
> R\> rdepthmedian(maxit = 10000, x = stackloss)
> $deepest
> intercept slope var. 1 slope var. 2 slope var. 3 
> \-35.37610619 0.82522124 0.44247788 -0.07964602 
> \`\`\`
> 
> where the first parameter is intercept and the remaining part represents the partial slops. 
> 
> When I compile all of the fortran code in a single binary using 
> 
> \`\`\`shell
> $ gfortran -shared -fPIC \*.f
> \`\`\`
> 
> I can bring all of the functionality into Julia using the FFI features. The estimated parameters can be re-calculated in Julia using 
> 
> \`\`\`Julia
> X = convert(Matrix, stackloss) 
> n, p = size(X)
> n = Int32(n)
> p = Int32(p)
> A = zeros(Float64, p)
> maxit = Int32(10000)
> iter = Int32(1)
> MDEPAPPR = Int32(3)
> result = ccall((:sweepmedres\_, "./a.out"), 
> Cint, 
> (Ref{Float64}, # X
> Ref{Int32}, # n
> Ref{Int32}, # np
> Ref{Float64}, # A
> Ref{Cint}, # maxit 
> Ref{Cint}, # iter
> Ref{Cint} # MDEPAPPR
> ), X, n, p, A, maxit, iter, MDEPAPPR)
> 
> println(A)
> \`\`\`
> 
> and the codes returns the same estimates as we obtained using R:
> 
> \`\`\`julia
> \[0.8252212389746946, 0.44247787604338223, -0.0796460177080886, -35.37610619462\] 
> \`\`\`
> 
> where the last term is intercept and first 3 estimates are partial slopes. 
> 
> The problem is, the package is an R package and I failed to make it done using BinaryBuilder.jl. 
> 
> \- Can any talented friends in this area help migrating this functionality into Julia?
> \- Can we standardize the toolchain that inputs an R package and prepare a jdll output in an easy way?
> 
> Sorry if I am bothering you for a specific issue. 
> 
> Thank you for considering my message.

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 22, 2023, 7:01pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/11 "2023-08-22T19:01:36Z")

</div>

Thank you @mkitti, it seems the binary package is available in Yggdrasil repository. I will use this as a dependency in LinRegOutliers.jl package and we will have one more robust regression technique for linear regression.

By the way, I once again saw how difficult and complex creating such a package could be. However, once the difficulty is overcome, we have a library that works on all platforms, and that’s what’s beautiful about it.

---

<div class="post-metadata">

### Author: ![mkitti](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mkitti/32/12459_2.png) [@mkitti](https://discourse.julialang.org/u/mkitti)
#### Post date: [August 22, 2023, 7:53pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/12 "2023-08-22T19:53:14Z")

</div>

The JLL package was ultimately published and registered here:

> **[GitHub - JuliaBinaryWrappers/mrfDepth\_jll.jl](https://github.com/JuliaBinaryWrappers/mrfDepth_jll.jl)**
>
> Contribute to JuliaBinaryWrappers/mrfDepth\_jll.jl development by creating an account on GitHub.

The main gist was the recipe below. The main thing that needed be added was a copy of the compiled shared library into `${WORKSPACE}/destdir/lib` or `$libdir`. We also needed to abstract out the fortran compiler rather than hard coding it, and install a proper license.

```julia
cd ${WORKSPACE}/srcdir/mrfDepth/src
$FC -shared -fPIC *.f -o libmrfDepth.${dlext}
cp libmrfDepth.${dlext} ${libdir}
install_license /usr/share/licenses/GPL-2.0+

```

The full recipe can be found here and was mainly just generated code from the wizard template.

> <https://github.com/JuliaPackaging/Yggdrasil/blob/0eb5e48617c2de4bba00af440aac5ebb389ca6a9/M/mrfDepth/build_tarballs.jl>

---

<div class="post-metadata">

### Author: ![jbytecode](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/jbytecode/32/17719_2.png) [@jbytecode](https://discourse.julialang.org/u/jbytecode)
#### Post date: [August 22, 2023, 7:59pm UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/13 "2023-08-22T19:59:12Z")

</div>

Great job, thank you again. I will follow the same semantics if I need further migrations.

---

<div class="post-metadata">

### Author: ![Marius\_Kruger](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/marius_kruger/32/904_2.png) [@Marius\_Kruger](https://discourse.julialang.org/u/Marius_Kruger)
#### Post date: [August 24, 2023, 9:16am UTC](https://discourse.julialang.org/t/how-about-hosting-c-c-fortran-rust-code-in-julia-packages/102962/14 "2023-08-24T09:16:38Z")

</div>

good idea, I recently found Cuda.jl and it helps a lot to be abke to deploy without having to separately install python and python modules…
