another issue, inline
Ittay Dror wrote:
Hi,
I'm working on adding C++ support to buildr. I already have a
prototype that builds libraries and executables in Linux. I'd like to
share some of the difficulties I had and request changes to buildr to
accommodate C++ more easily. (Right now, I've created parallel route
to that of building Java-like code)
compile
========
overview
--------------------
the compile method in project returns a CompileTask that is generic
and uses a Compiler instance to do the actual compilation. In C++,
compilation is also dependency based (.o => .cpp, sometimes
precompiling headers). Also, the same code can produce several results
(static and shared libraries, oj files with debug, profiling,
preprocessor defines turned on and off). [1]
there is the 'build' task, which is used as a stub to attach
dependencies to.
suggestion
---------------------
* there should be an array of compile tasks (as in packages)
* #compile should delegate the call to a factory method which returns
a task (again, as in packages)
* generic pre-requisites (like 'resources') should either be tacked on
'build' (relying on order of prerequisites), or the compile task can
be defined to be a composite (that is, from the outside it is a single
task, but it can use other tasks to accomplish its job).
package & artifacts
=========
overview
---------------
buildr has a cool concept that all dependencies (in 'compile.with')
are converted to tasks that are then simple rake dependencies.
However, the conversion is not generic enough. to compile C++ code
against a dependency one needs 2 paths: a folder containing headers
and another containing libraries. To put this in a repository, these
need to be packaged into one file. To use after pulling from the
repository, one needs to unpack. So a task representing a repository
artifact is in fact an unzip task, that depends on the 'Artifact' task
to pull the package from a remote repository.
furthermore, when building against another project, there is no need
to pack and unpack in the repository. one can simply use the artifacts
produced in the 'build' phase of the other project.
finally, in C++ in many cases you rely on a system library.
in all cases the resulting dependency is two-fold: on a include dir
paths and on a library paths. note that these do not necessarily
reside under a shared folder. for example, a dependency on another
project may depend on two include folders: one just a folder in the
source tree, the other of generated files in the target directory
suggestion
-------------------
While usage of Buildr.artifacts is only as a utility method, so one
can easily write his own implementation and use that, I think it will
be nice to be able to get some reuse.
* when given a project, use it as is (not 'spec.packages'), or allow
it to return its artifacts ('spec.artifacts').
* if a symbol, recursively call on the spec from the namespace
* if a struct, recursively call
* otherwise, classify the artifact and call a factory method to create
it. classification can be by packaging (e.g. jar). but actually, i
don't have a very good idea here. note that for c++, there need to be
a way of defining an artifact to look in the system for include files
and libraries (maybe something like 'openssl:system'? - version and
group ids are meaningless).
* the factory method can create different artifacts. for c++ there
would be RepositoryArtifact (downloads and unpacks), ProjectArtifact
(short circuit to the project's target and source directories) and
SystemArtifact.
I think that the use of artifact namespaces can help here as it allows
to create a more verbose syntax for declaring artifacts, while still
allowing the user to create shorter names for them. (as an example in
C++ it will allow me to add to the artifact the list of flags to use
when compiling/linking with it, assuming they're not inherent to the
artifact, e.g. turn debug on). The factory method receives the
artifact definition (which can actually be defined by each plugin) and
decides what to do with it.
ordering
=========
overview
-------------------
to support jni, one needs to first compile java classes, then run javah
to generate headers and then compile c code that implements these
headers. so the javah task should be able to specify it depends on the
java compile task. this can't be by depending on all compile tasks of
course or on 'build'.
suggestion
-------------------
when creating a compile task (whose name can be, as in the case of c++,
the result library name - to allow for dependency checking), also create
a "for ordering only" task with a symbolic name (e.g., 'java:compile')
which depends on the actual task. then other tasks can depend on that task
I hope all this makes sense, and I'm looking forward to comments. I
intend to share the code once I'm finished.
Thank you,
Ittay
Notes:
[1] I don't consider linking a library as packaging. First, the obj
files are not used by themselves as in other languages. Second,
packaging is required to manage dependencies, because in order for
project P to be built against dependency D, D needs to contain both
headers and libraries - this is the package.
--
--
Ittay Dror <[EMAIL PROTECTED]>