Migrating the Doxygen output to Sphinx

Slightly off-topic, but worth mentioning: If anyone wants to pick that up, Juan’s great work on that can be found here: https://github.com/RIOT-OS/RIOT/pull/11459

2 Likes

Yes for sphinx-build, no for antidox (unless someone can prove that it’s used in several projects). Even if breathe has its drawbacks (slow, etc), it’s more widely used, the project is active with a small community behind (not a single dev).

Just a side note,

@leandrolanzieri and me took some days a year ago to migrate Doxygen into readthedocs using Breathe (this is the [link @akshaim posted]Akshai(://riot-os.readthedocs.io/)).

We were aware of Juan’s work (and the reasons why he created antidox) but we tried to replicate the Breathe setup first before deciding to step into that. We were able to generate the documentation in an ok-ish time (and way under the time limits of RTD), so we decided to continue with Breathe

If we want to continue with Sphynx, we could publish those branches.

Curb your enthusiasm: Note that Breathe only generates “references” to all Doxygen objects. It won’t generate the output of Doxygen as it is. The finished work looks 100 times better than Doxygen, no doubts, but this means that we actually need to write documentation (which is desired, but takes a lot of time)

2 Likes

@jia200x I can work on the documentation part :slight_smile: Its just that now we have two theories. Breathe and antidox. Which should we opt for ?

1 Like

IMHO we shoud opt for breathe, when what @jia200x is saying is true: It appears Juan only created antidox to meet some timing constraints that are met by breathe now or anyway.

On the other hand, Juan still seems to be working on antidox, so maybe there is potential… But nevertheless I would always opt for the more mature project.

Makes sense. Lets make RIOT Beginner friendly.

1 Like

ERRATA:

The link above was Juan’s work (thanks @leandrolanzieri for pointing that out). We are trying to recover the branch now and remember where did we host those stuff :slight_smile:

This is the branch where we worked https://github.com/jia200x/RIOT/commits/pr/sphinx Currently many things are missing, but the output looks something like this:

I think @jia200x mentioned that somewhere there is a commit that adds the board info as well.

So was your output only generated from the READMEs? The fact that @jia200x said, we need to write the documentation, makes me now worried, that your solution does not include the Doxygen output to the generated Sphinx output, which Juan’s solution did.

It has been some time, but what I remember is that with breathe you get references to include Doxygen information (so you include the APIs documentation) and you add them to the .rst files where you write the documentation of the module.

Ok, but then Juan’s approach is superior (and might also explain, why your work wit breathe allowed it to be faster), because if you look at riot-os.readthedocs.org, you see that it also contains the content of the doxygen documentation.

It’s a different approach, yes. I am for writing the module documentation and add the api on a .rst file. I don’t see a problem there. Maybe having to do it explicitly will force use to improve the documentation of some modules, which are currently just a title and a list of functions.

I’m not arguing that the proposed branch is a final solution, or that it is better than Juan’s approach. I just shared it to have more options on the table, and as a possible starting point for further work.

Ok, but then Juan’s approach is superior (and might also explain, why your work wit breathe allowed it to be faster), because if you look at riot-os.readthedocs.org, you see that it also contains the content of the doxygen documentation.

IIRC antidox was not only a parser, it definitely did more stuff. But I think there are ways to print all “objects” at once (There are some “auto” objects), but the point is that per se the Doxygen documentation is just an API documentation.

The idea with Sphinx is to write better documentation, with nice references and rich text everywhere (in addition to the API doc). This is something we would need to do anyway in Doxygen if we wanted to improve our documentation.

1 Like

Maybe I am still misunderstanding how this come out (maybe an actual HTML output instead of a screenshot would help me there), but I think rewriting the whole API documentation too much work, work that was already done. Besides, doc should always stay with the code, otherwise it will get stale in an instance. So I don’t see really an advantage in generating .rst files that we then have to handfill ourselves.

I agree on that there is a lot more introductory text needed in the current documentation and that the output HTML of Doxygen is old-fashioned and outdated (XHTML wtf?). However, I’d also like to point out, that Doxygen is really powerful, when it comes to references and it supports rich text (or what do you believe all those markdown instructions are for)?

IMHO the biggest problem with our Doxygen right now is that search does not work properly.

E.g. it’s not possible to find xtimer_msleep, when searching for ADC you get the adc.h File Reference and have to navigate from there to the main ADC page.

If Sphinx can solve this, it would be a big win.

[26_2.png] benpicco Maintainer 15 February

IMHO the biggest problem with our Doxygen right now is that search does not work properly.

E.g. it¢s not possible to find xtimer_msleep, when searching for ADC you get the adc.h File Reference and have to navigate from there to the main ADC page.

the ADC page your are looking for is at the end of the search result. … but i don’t see a systematic behavoir for other terms.

If Sphinx can solve this, it would be a big win.

changing the framework only because the search engine doesn’t work as expected … hmm…

cheers matthias

For me this would be the main advantage of Sphinx.

One thing on my wish list is to be able to include code snippets in the documentation and have these compiled during one of the CI stages. Think along the lines of usage examples and code patterns. By having these compiled in the CI it forces us to update them on an API change. I haven’t looked whether there is a plugin for Sphinx for this (and I think a migration is worth the trouble without this feature).

I’ve heard quite some complaints from RIOT users about the search function and that it is hard to find relevant documentation. I have the same issue with other projects that also use Doxygen.

[14_2.png] bergzand Maintainer 16 February [40.png] jia200x:

  The idea with Sphinx is to write better documentation, with nice references and
  rich text everywhere (in addition to the API doc). This is something we would need
  to do anyway in Doxygen if we wanted to improve our documentation.

For me this would be the main advantage of Sphinx.

One thing on my wish list is to be able to include code snippets in the documentation and have these compiled during one of the CI stages.

+!

  [24_2.png] waehlisch:

  changing the framework only because the search engine doesn’t work as expected …
  hmm…

I’ve heard quite some complaints from RIOT users about the search function and that it is hard to find relevant documentation. I have the same issue with other projects that also use Doxygen.

from the documentation using Google search:

Client side searching

An additional advantage of this method is that it provides live searching, i.e. the search results are presented and adapted as you type.

This method also has its drawbacks: it is limited to searching for symbols only. It does not provide full text search capabilities, and it does not scale well to very large projects (then searching becomes very slow).

based on the current search experiences, i suppose, SERVER_BASED_SEARCH is set to NO in our setup

Hi all,

based on the current search experiences, i suppose, SERVER_BASED_SEARCH is set to NO in our setup

Yes, in RIOT is set to NO. I tested this feature with a local setup (it requirs PHP) and the documentation seems to improve a bit:

E.g searching ADC:

1.	Module ADCXX1C ADC device driver
	Matches: adc(5) adcxx1c_params_t(1) adcxx1c_res_8bits(1) adcxx1c_res_10bits(1) adcxx1c_res_12bits(1) adcxx1c_cycle_disabled(1) adcxx1c_cycle_32(1) adcxx1c_cycle_64(1) adcxx1c_cycle_128(1) adcxx1c_cycle_256(1) adcxx1c_cycle_512(1) adcxx1c_cycle_1024(1) adcxx1c_cycle_2048(1) adcxx1c_ok(1) adcxx1c_noi2c(1) adcxx1c_nodev(1) adcxx1c_nodata(1) adcxx1c_cb_t(1) adcxx1c(7) adcxx1c_t(1) adcxx1c_init(1) adcxx1c_read_raw(1) adcxx1c_enable_alert(1) adcxx1c_set_alert_parameters(1) adcxx1c_i2c_address(1) adcxx1c021(1) adcxx1c_res_default(1) adc081c(2) adc101c(2) adc121c(2)
2.	Module ADC
	Matches: adc_t(1) adc_line(1) adc_res_12bit(1) adc_res_16bit(1) adc_res_10bit(1) adc_res_6bit(1) adc_res_8bit(1) adc_res_14bit(1) adc_res_t(1) adc(31) adc_init(1) adc_sample(1) adc_undef(1) adc_sample()(3)
3.	Module ADCXX1C driver compile configurations
	Matches: adcxx1c(1) adcxx1c_param_i2c(1) adcxx1c_param_addr(1) adcxx1c_param_bits(1) adcxx1c_param_cycle(1) adcxx1c_param_alert_pin(1) adcxx1c_param_low_limit(1) adcxx1c_param_high_limit(1) adcxx1c_param_hysteresis(1)
4.	Member adc_conf_t::avg
	Matches: adc_conf_t(2) adc(2) adc_avg_max(1) adc_avg_none(1) adc_conf_t::dev(1) adc_conf_t::avg(1) adcx(2) adcx_sc3(1) adcx_sc1x(2) adc0_dp(1)
5.	Module Analog data conversion utilities
	Matches: adc(7) adc_util_map(2) adc_util_mapf(1)
6.	Module LIS3DH accelerometer
	Matches: adc(5) adc_data_size(1) adc_pd_mask(1)
7.	Member adc_conf_t::chan
	Matches: adc_conf_t(1) adc(1) adc_conf_t::chan(1)
8.	Member adc_conf_chan_t::pin
	Matches: adc_conf_chan_t(1) adc(1) adc_conf_chan_t::pin(1)
9.	Member adc_conf_t::dev
	Matches: adc_conf_t(1) adc(1) adc_conf_t::dev(1)
10.	Member adc_conf_t::dev
	Matches: adc_conf_t(1) adc(1) adc_conf_t::dev(1)
11.	Member adc_conf_chan_t::muxpos
	Matches: adc_conf_chan_t(1) adc(1) adc_conf_chan_t::muxpos(1)
12.	Member IRQn
	Matches: adc_irqn(2) adc_cmp_irqn(1)
13.	Member adc_chan_conf_t::reference
	Matches: adc_chan_conf_t(1) adc_chan_conf_t::reference(1)
14.	Member adc_chan_conf_t::input
	Matches: adc_chan_conf_t(1) adc_chan_conf_t::input(1)
15.	Member adc_chan_conf_t::dev
	Matches: adc_chan_conf_t(1) adc_chan_conf_t::dev(1)
16.	Member adcxx1c::arg
	Matches: adcxx1c(1) adcxx1c::arg(1)
17.	Member adc_chan_conf_t::acq_time
	Matches: adc_chan_conf_t(1) adc_chan_conf_t::acq_time(1)
18.	Member adcxx1c_params::i2c
	Matches: adcxx1c_params(1) adcxx1c_params::i2c(1)
19.	Member adc_conf_t::cmu
	Matches: adc_conf_t(1) adc_conf_t::cmu(1)
20.	Member adc_conf_t::pin
	Matches: adc_conf_t(1) adc_conf_t::pin(1)
21.	Member RTCIO_ADC_ADC2
	Matches: adc_adc2(1) adc2(1)
22.	Member adcxx1c_params::hysteresis
	Matches: adcxx1c_params(1) adcxx1c_params::hysteresis(1)
23.	Member adcxx1c_params::high_limit
	Matches: adcxx1c_params(1) adcxx1c_params::high_limit(1)
24.	Member adcxx1c_params::addr
	Matches: adcxx1c_params(1) adcxx1c_params::addr(1)
25.	Member adcxx1c_params::low_limit
	Matches: adcxx1c_params(1) adcxx1c_params::low_limit(1)
26.	Member adcxx1c_params::alert_pin
	Matches: adcxx1c_params(1) adcxx1c_params::alert_pin(1)
27.	Member adcxx1c_params::cycle
	Matches: adcxx1c_params(1) adcxx1c_params::cycle(1)
28.	Member adcxx1c_params::bits
	Matches: adcxx1c_params(1) adcxx1c_params::bits(1)
29.	Member adcxx1c::params
	Matches: adcxx1c(1) adcxx1c::params(1)
30.	Member adcxx1c::cb
	Matches: adcxx1c(1) adcxx1c::cb(1) 

Searching CoAP:

1.	Module Nanocoap small CoAP library
	Matches: coap_pkt_t(1) coap_opt_finish(2) coap_opt_finish_none(1) coap_handler_t(1) coap_method_flags_t(1) coap_block1_t(5) coap_resources(1) coap_resources_numof(1) coap_code(1) coap_get_code_class(1) coap_get_code_detail(1) coap_get_code(1) coap_get_code_raw(1) coap_get_id(1) coap_get_token_len(1) coap_get_total_hdr_len(1) coap_get_type(1) coap_get_ver(1) coap_hdr_data_ptr(1) coap_hdr_set_code(1) coap_hdr_set_type(1) coap_get_content_type(1) coap_opt_get_string(1) coap_get_location_path(1) coap_opt_location_path(1) coap_get_location_query(1) coap_get_uri_path(1) coap_opt_uri_path(1) coap_get_uri_query(1) coap_opt_get_next(1) coap_opt_get_opaque(1) coap_block_object_init(1) coap_block_finish(1) coap_block1_finish(1) coap_opt_block1(1) coap_block2_finish(1) coap_block2_init(1) coap_block_slicer_init(1) coap_blockwise_put_bytes(1) coap_blockwise_put_char(1) coap_get_block(1) coap_get_block1(1) coap_get_block2(1) coap_get_blockopt(1) coap_szx2size(1) coap_opt_add_block(1) coap_opt_add_block1(1) coap_opt_add_block2(1) coap_opt_add_uint(1) coap_opt_add_block1_control(1) coap_opt_add_block2_control(1) coap_opt_add_format(1) coap_opt_add_opaque(1) coap_opt_add_string(1) coap_opt_put_block(1) coap_opt_put_block1(1) coap_opt_put_block2(1) coap_opt_put_uint(1) coap_opt_put_block1_control(1) coap_opt_put_block2_control(1) coap_opt_put_string(1) coap_opt_put_location_path(1) coap_opt_put_location_query(1) coap_opt_put_uri_path(1) coap_opt_put_uri_query(1) coap_put_block1_ok(1) coap_put_option(1) coap_put_option_block1(1) coap_put_option_ct(1) coap_block2_build_reply(1) coap_build_hdr(1) coap_build_reply(2) coap_handle_req(1) coap_method2flag(1) coap_parse(1) coap_pkt_init(1) coap_reply_simple(1) coap_well_known_core_default_handler(3) coap_match_path(1) coap_has_observe(1) coap_clear_observe(1) coap_get_observe(1) coap(59) coap_format_none(2) coap_match_subtree(3) coap_opt_finish_payload(1) coap_type_con(2) coap_get_block1()(1) coap_parse()(1) coap_resource_t::methods(1) coap_get(1) coap_code_204(4) coap_type_non(1) coap_type_ack(1) coap_type_rst(1) coap_format_xxx(1) coap_opt_get_next()(1) coap_put_option_block1()(1)
2.	Module CoAP compile configurations
	Matches: coap(1) coap_ack_timeout(5) coap_random_factor(2) coap_ack_variance(1) coap_max_retransmit(1)
3.	Module CoAP defines
	Matches: coap(3) coap_port(1)
4.	Member coap_hdr_t::code
	Matches: coap_hdr_t(1) coap(1) coap_hdr_t::code(1)
5.	Member coap_optpos_t::opt_num
	Matches: coap_optpos_t(1) coap(1) coap_optpos_t::opt_num(1)
6.	Member coap_pkt_t::options
	Matches: coap_pkt_t(1) coap_pkt_t::options(1)
7.	Member coap_link_encoder_ctx_t::content_format
	Matches: coap_link_encoder_ctx_t(1) coap_link_encoder_ctx_t::content_format(1)
8.	Member coap_hdr_t::id
	Matches: coap_hdr_t(1) coap_hdr_t::id(1)
9.	Member coap_hdr_t::ver_t_tkl
	Matches: coap_hdr_t(1) coap_hdr_t::ver_t_tkl(1)
10.	Member coap_optpos_t::offset
	Matches: coap_optpos_t(1) coap_optpos_t::offset(1)
11.	Member coap_block1_t::more
	Matches: coap_block1_t(1) coap_block1_t::more(1)
12.	Member coap_link_encoder_ctx_t::flags
	Matches: coap_link_encoder_ctx_t(1) coap_link_encoder_ctx_t::flags(1)
13.	Member coap_block1_t::blknum
	Matches: coap_block1_t(1) coap_block1_t::blknum(1) 

As a side discussion, IMO neither Doxygen nor Sphinx will leverage the fact that we actually need to write documentation. With the latter search, it’s not obvious how to use CoAP. Of course it helps to have API documentation, but this won’t replace end user documentation (see this very old issue)