diff --git a/CMakeLists.txt b/CMakeLists.txt index e5052fa..1621834 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -55,6 +55,10 @@ if (Protobuf_FOUND) else() message("No installed Protobuf has registered itself with CMake.") + # TODO: When we upgrade to CMake 3.13 minimum, use its protobuf_generate() + # and figure out how to not get it to pass two -I options that then make + # protoc claim to succeed but not actually write any files. + # Fall back to FindProtobuf.cmake and hope it is a version that works with the installed Protobuf find_package(Protobuf REQUIRED) @@ -65,7 +69,14 @@ else() endif() - +# We now have PROTO_SRCS and PROTO_HDRS. But the files for them don't generate +# until build time. If we add PROTO_SRCS as sources for two different library +# targets (at least with FindProtobuf.cmake), each library target gets Makefile +# rules to run protoc, but they try to write to the same output location. If +# they run in parallel, this causes corruption of the generated files. So we +# need to sequence things so the Protobuf compiler runs only once, before any +# of the libraries try to build. +add_custom_target(run_protoc SOURCES ${PROTO_SRCS} ${PROTO_HDRS} DEPENDS ${PROTO_SRCS} ${PROTO_HDRS}) # Find threads @@ -149,6 +160,10 @@ set_property(TARGET vgio_static PROPERTY POSITION_INDEPENDENT_CODE OFF) add_dependencies(vgio link_target) add_dependencies(vgio_static link_target) +# Don't build any object files until the protoc-generated sources are generated, once. +add_dependencies(vgio run_protoc) +add_dependencies(vgio_static run_protoc) + # Add an alias so that library can be used inside the build tree, e.g. when testing add_library(VGio::vgio ALIAS vgio) diff --git a/include/vg/io/alignment_io.hpp b/include/vg/io/alignment_io.hpp index e9d7bde..f91edaa 100644 --- a/include/vg/io/alignment_io.hpp +++ b/include/vg/io/alignment_io.hpp @@ -100,11 +100,19 @@ gafkluge::GafRecord alignment_to_gaf(const HandleGraph& graph, bool frag_links = true); // TODO: These will need to be able to take a forward translation to read named-segment GAF. /// Convert a GAF alignment into a vg Alignment. The alignment must be in node ID space. +/// +/// All tags are preserved in the "tags" annotation, except those interpreted +/// to construct the Alignment. If the "cg" tag was used to construct the +/// alignment, it will be annotated with "from_cg" true. void gaf_to_alignment(function node_to_length, function node_to_sequence, const gafkluge::GafRecord& gaf, Alignment& aln); /// Convert a GAF alignment into a vg Alignment. The alignment must be in node ID space. +/// +/// All tags are preserved in the "tags" annotation, except those interpreted +/// to construct the Alignment. If the "cg" tag was used to construct the +/// alignment, it will be annotated with "from_cg" true. void gaf_to_alignment(const HandleGraph& graph, const gafkluge::GafRecord& gaf, Alignment& aln); diff --git a/src/alignment_io.cpp b/src/alignment_io.cpp index d4dd3da..a0335b2 100644 --- a/src/alignment_io.cpp +++ b/src/alignment_io.cpp @@ -1116,6 +1116,7 @@ void gaf_to_alignment(function node_to_length, } } + std::stringstream extra_tags; for (auto opt_it : gaf.opt_fields) { if (opt_it.first == "dv") { // get the identity from the dv divergence field @@ -1143,8 +1144,27 @@ void gaf_to_alignment(function node_to_length, } else if (opt_it.first == "sa") { // we use "sa" as opposed to "SA" for our particular articulation of supplementary alignments decode_supplementary_tag_value(aln, opt_it.second.second, node_to_length); + } else if (opt_it.first == "cs" || opt_it.first == "cg") { + // Skip cs and cg fields since we already read them. + // So do nothing here. + } else { + // Other optional fields need to go into the "tags" annotation, + // tab-separated, as in SAM. + if (extra_tags.tellp() != std::streampos(0)) { + // Separate from previous tag with a tab + extra_tags << "\t"; + } + // TODO: Deduplicate with serialization in gfakluge.hpp? + extra_tags << opt_it.first << ":" << opt_it.second.first << ":" << opt_it.second.second; } } + if (extra_tags.tellp() != std::streampos(0)) { + // Attach the tags annotation + auto* annotation = aln.mutable_annotation(); + google::protobuf::Value extra_tags_value; + extra_tags_value.set_string_value(extra_tags.str()); + (*annotation->mutable_fields())["tags"] = extra_tags_value; + } } void gaf_to_alignment(const HandleGraph& graph,