Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dependencies issue #27

Merged
merged 15 commits into from Sep 2, 2022
Merged

Dependencies issue #27

merged 15 commits into from Sep 2, 2022

Conversation

FabrizioSandri
Copy link
Owner

Following a conversation with my mentor @tdhock, we determined that RcppDeepState should not execute the install.packages function within the deepstate_create_makefile method since it is bad practice.

Furthermore, running install.packages does not install the package dependencies, resulting in the shared object file not being generated. The error message for the hermiter package was

ERROR: dependency 'BH' is not available for package 'hermiter'

Instead of terminating, RcppDeepState kept running, consequently compiling the src/*.cpp with weird include problems. To solve this issue, I replaced the installation command with devtools::install and moved it to the action code. Furthermore, I modified the conditions such that if the shared object is not generated, an error is generated and the execution is terminated.

Related to:

@FabrizioSandri
Copy link
Owner Author

Stopping if the shared object files are missing is not the best option. Instead, if they are absent, we should try to create them first and then quit if they are still not there. This is what I just did with my most recent commit.

Proof of concept

To construct the shared object, the user must call the deepstate_pkg_create method. In certain circumstances, however, the user analyzes a single function rather than the complete package. The shared objects are not created in this situation. For instance, the user can execute

└─RcppDeepState::deepstate_fun_create(path, "rcpp_write_index_outofbound")
  └─RcppDeepState::deepstate_create_makefile(package_path, function_name)

The shared object will not be constructed in this situation. To address this issue, I included another check in the deepstate_create_makefile that attempts to recreate the shared object if it is missing. If they are not present, the execution will be terminated with an error.

@tdhock
Copy link
Collaborator

tdhock commented Aug 30, 2022

I don't understand why the shared object/so file would ever be absent, if the package was installed? Can you clarify / explain what files are created in your rcpp_write_index_outofbound example? Shouldn't there be a shared object created for whatever package that function is defined in?

@FabrizioSandri
Copy link
Owner Author

To clarify, if a user just wants to analyze a single function rather than the entire package, he may use the deepstate_fun_create function to create the test harness, deepstate_fuzz_fun to compile it, and deepstate_analyze_fun to analyze it.

Example: suppose a user wants to analyze rcpp_write_index_outofbound of the testSAN package without analyzing the entire package. The user performs the following steps:

pkg_path <- "/home/fabri/test/testHarness/RcppDeepState/inst/testpkgs/testSAN"
fun_name <- "rcpp_write_index_outofbound"

deepstate_fun_create(pkg_path, fun_name)
deepstate_fuzz_fun(pkg_path, fun_name)
deepstate_analyze_fun(pkg_path, fun_name)

The issue is that, before I implemented the modifications in this pull request, the R CMD install command is never executed to produce the shared object: R CMD install is only run when the user invokes the deepstate_pkg_create function, or in other words when the user tests the full package. As a result, the shared object is created only when the user tests the full package.

I don't understand why the shared object/so file would ever be absent, if the package was installed?

The package is installed using R CMD install, but only if the user first executes deepstate_pkg_create, or else the shared object files are missing. The shared object is not generated in the preceding example because deepstate_pkg_create is never called in the sequence of function calls. The solution is to include a second check in the makefile generating procedure to check that the shared object file is there. As a result, even if the user does not explicitly execute deepstate_pkg_create, the shared object will still be generated due to this second check.

@tdhock
Copy link
Collaborator

tdhock commented Aug 31, 2022

ok, thanks for the detailed explanation. I think I understand now. Basically, the user may be trying to compile a test harness in a source package which has not yet been installed on the system. The confusing part for me was that R CMD INSTALL is called in this case not actually for its main purpose of installing to the system library, but for its side effect of compiling the cpp files in the src directory, and creating a so file in there. Right?

@FabrizioSandri
Copy link
Owner Author

FabrizioSandri commented Aug 31, 2022

The confusing part for me was that R CMD INSTALL is called in this case not actually for its main purpose of installing to the system library, but for its side effect of compiling the cpp files in the src directory, and creating a so file in there. Right?

Yes, this is correct. Now I'm attempting to figure out why this pull request's CI is failing. It appears to be due to the following error message caused by the function system("R CMD INSTALL", ...)

  'R' should not be used without a path -- see par. 1.6 of the manual

I tried running the tests locally and they were successful, but using r-lib/actions causes CI to fail with this issue.

@tdhock
Copy link
Collaborator

tdhock commented Aug 31, 2022

I believe this refers to the following from https://cran.r-project.org/doc/manuals/r-release/R-exts.html#Writing-portable-packages

Do not invoke R by plain R, Rscript or (on Windows) Rterm in your examples, tests, vignettes, makefiles or other scripts. As pointed out in several places earlier in this manual, use something like

"$(R_HOME)/bin/Rscript"
"$(R_HOME)/bin$(R_ARCH_BIN)/Rterm"

with appropriate quotes (as, although not recommended, R_HOME can contain spaces). 

@tdhock
Copy link
Collaborator

tdhock commented Aug 31, 2022

rather than using system("R CMD INSTALL path/to/pkg") I wonder if you could use install.packages("path/to/pkg", repo=NULL) ? or devtools::install("path/to/pkg") ?

@FabrizioSandri
Copy link
Owner Author

FabrizioSandri commented Sep 1, 2022

You are correct! Thank you for your help; this resolved the issue. I changed the system("R CMD INSTALL path/to/pkg") call to install.packages("path/to/pkg", repo=NULL). I also deleted the previously mentioned system("R CMD INSTALL path/to/pkg") call from the deepstate_pkg_create function: shared objects are already checked for existence inside the makefile generation procedure, and if they are not present, they are generated. In this manner, each sequence of function calls will cause the shared object file to be generated.

Regarding the use of devtools::install("path/to/pkg"), I believe it is the user's duty to ensure that all of the dependencies of the package are installed.
In reality, I introduced another step within the makefile creation procedure that checks whether the shared object was not created after running install.packages(...); if it was not created, it indicates that a dependency is missing and the user will be notified with an error.

if (length(Sys.glob(shared_objects)) <= 0) {
  error_msg <- paste("ERROR: the shared object for your package cannot be",
                     "generated. This is probably caused by a missing",
                     "dependency. Please install all the dependencies for",
                     "your package.")
  stop(error_msg)
}

As discussed during the conversation we had on Tuesday I will ensure that RcppDeepState-action installs the missing package dependencies running devtools::install("path/to/pkg") before running RcppDeepState. I have implemented this in the following pull request

As we mentioned on Tuesday, I will make sure that RcppDeepState-action installs any missing package dependencies by executing devtools::install("path/to/pkg") before launching RcppDeepState. This is what I've done in the following pull request:

install.packages(package, repo=NULL)

if (length(Sys.glob(shared_objects)) <= 0) {
error_msg <- paste("ERROR: the shared object for your package cannot be",
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you don't need a paste and intermediate error_msg variable here, instead just use

stop(
  "the shared object ",
  "for your")

also please remove ERROR: since R adds that automatically, to avoid displaying Error: ERROR: etc.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fixed with commits f957075 and f739ebc

makevars_file <- file.path(package, "src", "Makevars")
if (dir.exists(file.path(package, "src"))) {
makevars_content <- "PKG_CXXFLAGS += -g \n"
write(makevars_content, makevars_file, append=TRUE)
makevars_content <- "PKG_CXXFLAGS += -g \n"
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is there any reason to have a different/non-standard 4 space indent here? if not can you please change back to 2 space indent, which seems conssitent with the surrounding code.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake, I updated this portion of code with commit f957075

NAMESPACE Outdated
Comment on lines 33 to 35
import(utils)
import(xml2)
importFrom(utils,unzip)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typically to avoid confusion, you should not use both importFrom(utils,unzip) and import(utils). what other function from utils are you using? Please either add that to the importFrom, or remove the importFrom, keep the import, and add utils:: prefix to the R code from utils, for example utils::unzip

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm using unzip and install.packages from utils. If I use import for utils, I get the following warning:

Warning: replacing previous import ‘Rcpp::prompt’ by ‘utils::prompt’ when loading ‘pkgA’

There is most likely some conflict between utils and Rcpp. Instead, I replaced import with importFrom with commit 11eaa1b.

Comment on lines 71 to 73
stop("ERROR: the shared object for your package cannot be generated.",
"This is probably caused by a missing dependency. Please install",
"all the dependencies for your package.")
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

> stop("ERROR: one sentence.", "Another sentence.")
Error: ERROR: one sentence.Another sentence.

please remove ERROR: and use a single argument to stop:

stop("One sentence. Another sentence.")

usually it is preferable to have 80 character max lines, and break lines like you do here, but for long character strings used in messages, it is preferable to not break them over multiple lines, to facilitate translation -- translators would have to translate each string separately. see https://github.com/MichaelChirico/potools for more info

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for your detailed explanation; I followed your suggestions and updated this with commit 3ede877.

@tdhock
Copy link
Collaborator

tdhock commented Sep 1, 2022

great!

Comment on lines 43 to 44
compiler_cppflags <- paste(cppflags, collapse=" -I ")
cppflags_write <- paste0("CPPFLAGS=-I",compiler_cppflags)
Copy link
Collaborator

@tdhock tdhock Sep 1, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this logic tested? I thought there was supposed to be no space between -I and the include path?
anyway please remove repetition of -I in this logic. I believe it should be paste(paste0("-I", cppflags), collapse=" ")

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good catch! There should be no space between -I and the include path. I tested this locally and it works, but I'll let CI finish to ensure that everything is working correctly.

Updated with commit 179ac76

Comment on lines -50 to +48
compiler_ldflags <- paste0("-L", rinside_lib, " -Wl,-rpath=", rinside_lib)
compiler_ldflags <- paste(compiler_ldflags, "-L${R_LIB} -Wl,-rpath=${R_LIB}")
compiler_ldflags <- paste(compiler_ldflags, paste0("-L", deepstate_build, " -Wl,-rpath=", deepstate_build))
write_to_file <- paste0(write_to_file, "LDFLAGS=", compiler_ldflags, "\n")
ldflag <- function(path) paste0("-L", path, " -Wl,-rpath=", path)
ldflags <- c(ldflag(rinside_lib), ldflag("${R_LIB}"), ldflag(deepstate_build))
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this is better! nice cleanup. the intent is much more clear this way.

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@FabrizioSandri
Copy link
Owner Author

FabrizioSandri commented Sep 2, 2022

@tdhock As mentioned during the meeting, I have published a new blog article on the beta testing results. If you agree, I'll merge this pull request as well as FabrizioSandri/RcppDeepState-action#20.

@tdhock
Copy link
Collaborator

tdhock commented Sep 2, 2022

sounds great please merge!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

2 participants