Is there documentation somewhere explaining how to do the latter? Or can someone help me with doing the latter?
I can't find any documentation explaining where to put the commands in a Pkg to actually git clone flint, build it, install it and set up paths for Nemo. Given the complexities of installing flint for the user, I'd like to have the Julia package manager do this automatically if at all possible. And I see it does seem to be possible. I just can't figure out how.
1) You can try looking at other packages to see the structure.
Code goes is `src/`
(and you'll need a `Nemo.jl` in there that will be what Julia runs when you say `using Nemo`).
Tests go in the `tests` folder; you should have a file `runtests.jl` in there that runs the tests for your package (if you want Julia's auto-testing stuff to work).
A file named REQUIRE is where any dependencies on other Julia go; it is also where you specify compatible versions of Julia. Every package has one of these, so you can look at them for examples to see the syntax. You probably want a line like `julia 0.3-` if you believe you package works for 0.3 and will work for 0.4, but not in 0.2.
Like most OSS projects: license in LICENSE.md, some documentation in README.md. (*.md means a plain text Markdown file; there's flexibility on plain text format/filename here; these are just what's made by default by `Pkg.generate`).
This is enough for people to get your package installed via the Julia package manager by running `Pkg.clone("https://github.com/wbhart/nemo")`.
Since Pkg.clone will put you package in the "right" place (i.e. where all your other Julia packages are installed), you'll be able to follow the normal package publishing (register with METADATA) instructions.
You should also search this mailing list for past BinDeps questions, as there have been a number of them. Looking at other packages that use BinDeps can also be very helpful; Cairo.jl is an example, but anything that wraps C libraries would probably be helpful.
Is there documentation somewhere explaining how to do the latter? Or can someone help me with doing the latter?You could run `Pkg.generate("Nemo")` and then copy and commit (some of) the resulting files in your own Nemo git tree; there aren't very many.
I can't find any documentation explaining where to put the commands in a Pkg to actually git clone flint, build it, install it and set up paths for Nemo. Given the complexities of installing flint for the user, I'd like to have the Julia package manager do this automatically if at all possible. And I see it does seem to be possible. I just can't figure out how.The Pkg manager will look for a file called `MYPKG/deps/build.jl` and run that if it exists. That's just a Julia file, so you can do whatever you want there (shell out, etc.).
One option is to use the BinDeps package which provides primitives for interacting with various package managers and build systems:
https://github.com/JuliaLang/BinDeps.jlA very advanced and fully-developed usage example can be found in the Cairo package, which has Autotools, Apt, Yum, and several other targets:
https://github.com/JuliaLang/Cairo.jl/blob/master/deps/build.jlThere are a number of other examples to draw from. Hopefully the above links will give you a sense of where to start. I can help out on Linux and Windows (@ihnorton on github).
This was what I thought of trying first. But I couldn't figure out how it worked out what GitHub repository to associate this with, or whether it would try to create one, possibly scrubbing my existing nemo repository on GitHub. Obviously I don't want to lose my commit history.
It also isn't clear where Julia creates the empty git repository. In the current directory? Or in some subdirectory of the Julia source tree?
For the most part I can just run configure, make, make install for now and set some library paths (if I can figure out what kind of system I am on).
> Firstly, GMP 5 is currently a drop-in replacement for MPIR for us. We prefer to use MPIR since I am the maintainer of the latter, and significant work has gone into making various features faster.If the reverse is true, and MPIR would be a drop-in replacement for GMP for Julia, then it could also be a possibility that Julia could try to use MPIR instead of GMP in the future. I'm not aware of the specific differences other than MPIR intends to be more compatible with MSVC, and compiling Julia with MSVC is an ongoing experiment that I've done a fair amount of work on. Having the maintainer of a dependency library happen to be a user of Julia might be convenient for... reasons.> For flint we definitely require the latest bleeding edge git version. Even the last official release from us, flint-2.4.4, will not work with Nemo.We can experiment with bleeding edge git instead. We'll have to see how many more changes will be needed. Presumably you can tag a release of flint once we're happy things are working?
> The CP text file is absolutely enormous (nearly a megabyte). Encoding it as a string is certainly out of the question (we strictly adhere to the ANSI standard, which limits strings to something like 750 bytes). We've discussed many other ways of handling it, and numerous people have tried various things. It's a major pain in the backside, but totally necessary to have it (mathematically speaking).>> Currently it is not too bad in that once flint is installed, so is the file, in a location with a fixed offset from the library (which will have been specified by --prefix). If the user chooses to build flint in the source tree, it is located in a fixed location within the source tree which flint can also find it. This is all fine, so long as nothing gets moved after compilation and installation, which is the usual case, it seems.So is the path a relative path between the library and the text file, or an absolute path to the text file? When installing from a binary we can keep the relative path consistent pretty easily, absolute path definitely not. If it's an absolute path, would it be feasible to check the compile-time defined path first by default (as is done currently), but fall back to using an environment variable or other runtime path initialization method if the default location fails?
> The problem with linking against Julia's GMP and MPFR was as follows. We can tell Julia where to find flint by pushing to DL_LOAD_PATH. But this only tells Julia where to find flint. The system linker is the one that tries to subsequently link flint with MPIR and MPFR, and it hasn't got a clue where to find them. What we push on DL_LOAD_PATH is irrelevant, as only Julia knows about that. This actually causes Julia to report that it can't find flint. I spent many, many hours figuring that one out.I'm not proposing to push anything to DL_LOAD_PATH for GMP or MPFR. Rather we tell flint's build system at compile time where to find Julia's GMP and MPFR via -L. Those libraries will always be either at a consistent relative path vs JULIA_HOME,
or in standard system library paths if the user (or package manager) built Julia against system GMP/MPFR. I think it would be safe to check if joinpath(JULIA_HOME,"..","lib","libgmp.$(sys.dlext)") is openable via dlopen_e, and if not then falling back to find_library(["libgmp"]).
> Now it occurs to me that perhaps if we build flint against Julia's GMP and MPFR (assuming GMP is version 5 and MPFR version 3.1), then because Julia's libs are placed in the path by Julia, the system linker might just find them. That hadn't occurred to me as a possibility. The obvious problem is GMP is not MPIR and we are limited to using whatever version of GMP Julia chooses. Actually, maybe the git version of flint already supports GMP 6 nowadays too.For Julia 0.3.0, GMP is version 5.1.3, MPFR is version 3.1.2. Check https://github.com/JuliaLang/julia/blob/768187890c2709bf2ff06818f40e1cdc79bd44b0/deps/Versions.make for the default version numbers used. On Julia master, GMP has been bumped to 6.0.0.
> Also, flint uses libgcc_s and pthreads (and libm). We've currently set it up to statically build libgcc_s into flint, but we can't do that with pthreads. Initially at least we could disable pthreads when building flint (there is an option for it) but I guess in the long run we won't want to do that. I guess we can for now, but it seems like a compromise.You don't need to do this if you use WinRPM. If libgcc_s and/or pthreads are dynamically linked, the RPM packaging scripts on the build service detect that and mark the dll's as dependencies, so they get correctly downloaded when you install the package. Linking dynamically will make your binaries smaller, and many other things also link to these same libraries.
> Regarding licenses, I would guess the GPL v3 and LGPL v3 license texts need to be distributed with Julia binaries, along with a written offer to provide the source code (or the actual source code). Certainly the LGPL allows Julia to dynamically link against LGPL libraries without becoming a derivative work. I don't want to make absolute statements about that issue, as IANAL, but I'd be interested in more details of how Julia is satisfying the conditions summarised here http://en.wikipedia.org/wiki/GNU_General_Public_License#Terms_and_conditionsLICENSE.md was clarified recently, and DISTRIBUTING.md has some additional information on this too. I don't think any of Julia's required dependencies are GPL-3 only, it looks like all the GPL ones are either GPL-2 or GPL-2+. Binaries of flint would need to include its own license, but flint is not being distributed with Julia here, just available to easily download in a user-triggered fashion.
> I didn't realise @unix_only was the opposite of @windows_only. I thought unix meant Free BSD, Net BSD, Unix, etc. And I couldn't see a way to combine Unix, Linux and OSX using the macros. Given that OSX is probably going to need something special, I'm not sure what the best combination of macros will be.OSX is a Unix. It is special and needs its own modified code much of the time, yes.> Popcnt is processor dependent. TLS is more OS dependent and I think available on Mingw. We can just disable hardware popcnt. It's not vitally important for more than about one noncritical function.The TLS check passes on a local MinGW configure. Should I enable TLS then? I'll leave popcnt disabled if you recommend as much.
> We tend not to use tags. But there's no problem introducing a named tag to pin things.Any reason why not? Your code is on github but your releases aren't, would be great if it was possible to track exactly which commits correspond to exactly which numbered release version.
> The way it currently works is the user will specify --prefix. This is where libflint will be installed (in a subdirectory called lib). Obviously a default is chosen otherwise.>> Flint is at first built inside its own source tree. Flint knows where to find the file relative to this source tree.>> But when make install is issued, it will be moved across to --prefix.>> As flint is compiled, --prefix is used to generate an absolute path where the text file will be stored, and this is baked into the library, which then also looks in this absolute path.>> Of course the absolute path is computed at compile time to be some path relative to --prefix. It is passed to the relevant parts of flint via a -D define.None of this is going to work if you want the library to be usable on a different machine than it gets compiled on. That's a pretty big restriction to put on your users. A bit like using Gentoo - some people think it's fun out of masochism or something, but not many. Most users would rather save time and use binaries wherever possible (assuming the results are the same and you don't introduce any compatibility problems - if you use an automated build service and a package manager these are easy).
> I don't know of a way to encode a path relative to where the library is installed. That would be very useful, if possible. But I'm not sure if it can be done.I'm actually not sure how fopen() with relative paths would work inside library code - it might depend on the current working directory of the calling process, which is also something you probably shouldn't be imposing restrictions on. This path is going to need to be runtime configurable, I don't see any other way around it.
Unless you want to generate the file in such a way that it becomes valid C syntax assigning into one string per line or an array of integers per line, then use it during compilation as a .c or .h file.> Since git is installed with Julia, I'd like to git clone flint as part of the install process, so that the user always has the source code of flint (and the license, etc).This isn't necessary. The flint source code is on github, it's pretty simple to document that and point people to the right place if they want to look at it. Keep in mind that not all Julia package users are going to understand or care about the source code of a C library. The Julia package existing and providing access to some of the functionality is enough for many users.> Flint is GPL, not LGPL. There is no linking exemption for flint. On the other hand, the FSF seems to be pretty isolated in its position that dynamic linking to a library results in a derived work. Fortunately there is almost no FSF code in flint and it is all LGPL'd. No one else is going to care.I don't know if we've gotten a clear legal intepretation of exactly where Julia's ccall falls with respect to licensing. I don't think it's exactly the same thing as linking.
If your non-GPL Julia package depends on a GPL library and is going to automatically download that GPL library (either from source or from a binary) as part of its installation, then you should clearly document that fact. There are companies that forbid their employees from using or looking at GPL code.
> I think I will get things going temporarily on Windows by modifying PATH first. Then I will promise a binary distribution method to come, which we can work on.Alright. Just to warn you again, plenty of MinGW users refuse to add MinGW permanently to PATH, due to the compatibility issues that introduces. More often than not you need to work with several different subtly incompatible toolchains, and putting any of those on PATH permanently is counter-productive. So this installation method is something that you may get to work on your machine, but it's unlikely to work many other places.
> Unfortunately it doesn't even work on my machine. It seems ok for some calls into the dll, but as soon as I try to say print something using a function in the MPIR dll it segfaults. I suppose it must be linked against subtly different Microsoft dll's than Julia and some kind of conflict results.Or maybe different GCC dll's. Exactly which version of MinGW-w64 are you using?
Might not be compatible with what was used to build Julia. Or there could be some issue due to having gmp and mpir both loaded within the same process?
We've seen sort-of-similar issues with blas and lapack and various packages, though not so much on Windows.> The problem must be what libtool is doing on mingw64. Make install doesn't even copy the generated dll across to the install directory, so you have to do this manually.Hm, yeah, libtool can be very picky, especially when it comes to dll's. I think I've used the "subtle and quick to anger" quote on this list before when talking about libtool... I've found configuring with lt_cv_deplibs_check_method=pass_all can sometimes help.> I also can't build flint against the Julia mpir and mpfr since Julia doesn't seem to distribute the gmp.h and mpfr.h files, and flint requires these when building.Oh, right, damn. Sorry I forgot about that! That is an issue, maybe we should open a separate discussion on that general topic. It has come up before that various packages would like to link against the same libraries as Julia (in the Blas and Lapack cases we're building with an incompatible ABI which makes this actually not a good idea in most cases, but for GMP and MPFR I think we're configuring them in the default way), so installing the corresponding headers would actually be necessary.Even though I'm not entirely sure what Nemo or Flint do or whether I would personally have a use for them, I have some strange desire to see more Julia packages be painless to install cross-platform and want to help here.
Let me know how the runtime configuration of the text file location goes,
then I can mock up what BinDeps would look like. It should simplify your deps/build.jl script by automating the standard download, extract, configure, make steps. There are also some Julia idioms like joinpath("a","b") that would be cleaner than what you're doing now with if statements to switch between forward slashes and backslashes, and things likecd(newdir) do...endthat work in a nicer way including returning to the old directory even on failure.
I've compiled many many dozens of libraries using MinGW-w64 on MSYS, and cross-compiling from Cygwin and various Linux distributions, and not encountered nearly as many problems as you seem to be. Pretending to be autotools but hacking it up yourself is the worst possible thing you could do - you're completely nonstandard and nonfunctional in cross-compilation for example, and you have as many or more dependencies - requiring bash for example is often not acceptable on FreeBSD and similar systems.
Part of the problem is the way MSYS2 identifies itself changes depending on what environment variables you have set (or which bat file you start it with). The MSYS uname is unrecognized by autotools because MSYS2 is new, and you almost never want to actually be compiling with the MSYS host, since that causes your application to link to the msys-2.0.dll posix compatibility layer.
It's like using the standard gcc in Cygwin, any users would need Cygwin and the associated GPL posix runtime library to use the compiled code. The MINGW64 uname is also new and unrecognized, and totally nonstandard. This is why you should be querying the COMPILER for information about what system the generated code is supposed to run on, NOT the build environment.
The accepted GNU triples for MinGW are:i686-pc-mingw32: MinGW.org 32 bit compiler, outdated and obsolete, don't use thisi686-w64-mingw32: 32 bit compiler from MinGW-w64 project, use this for 32 bit hostx86_64-w64-mingw32: 64 bit compiler from MinGW-w64 project, use this for 64 bit hostYes the names are confusing and make no sense, but this is the GNU standard that every other conforming project in the world is using. LLVM decided to go out on a limb and rearrange some of these names recently, adding to the confusion, but GCC, autotools, and MinGW are unlikely to follow their lead.
> I will have to look into that. It doesn't sound like something we want. Though I don't really understand why changing the host should change the way gcc compiles code, unless it does so for cygwin itself.Changing the host changes which compiler gets used to create the binaries. In Cygwin or Linux, you can call the MinGW compilers by providing --host=x86_64-w64-mingw32 or similar, if you're using conventional autotools. It's also possible in Cmake but it's about 5 lines worth of flags (or a toolchain file with the same content) - it works, eventually, but it's really picky.
> It was my understanding that the Mingw compiler could be used from Cygwin. Perhaps I am confused about it, but it seems like interrogating the compiler may not give the information we need.Right, but when you configure with --host=x86_64-w64-mingw32 in Cygwin or Linux, you're using a cross-compiler that is prefixed by the host triple: x86_64-w64-mingw32-gcc and similar for binutils. So you can't just ask "gcc" for information - in a lot of ways MSYS(2) is a hack to avoid worrying about MinGW cross-compilation, and it leads to some bad ways of doing things. I think it's better to do the work to make a library possible to cross-compile, than to give up and say MSYS(2) is the only method of compiling it for Windows. I've been cross-compiling Julia itself and all of its dependencies from both Linux and Cygwin for months, I very rarely touch MSYS(2) any more.
> We can't use the accepted gnu triples in MPIR and that has always been the case for GMP too. They don't give nearly enough information for our needs.Of course they don't provide a complete story when you're worrying about assembly and various SIMD instruction sets. But that's not the GNU triple's job. That information should be determined and represented separately, you're not going to include this kind of information in the host prefix of the name of a cross-compiler executable for example.
GMP is also a pretty bad actor in terms of its autotools usage - making a symlink to libgmp.dll called libgmp.lib in lib/ is completely the wrong thing to do for MinGW.
Not your fault I know, but sounds like you may have inherited some autotools abuses from GMP.