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

Add Crystal.main #4998

Merged
merged 2 commits into from Sep 19, 2017
Merged

Add Crystal.main #4998

merged 2 commits into from Sep 19, 2017

Conversation

asterite
Copy link
Member

@asterite asterite commented Sep 17, 2017

Fixes #4793
Closes #4793

Please read the doc comments in the commit.

As an example, to implement what is needed in #4793 one can now write:

@[Link("allegro")]
lib LibAllegro
  fun al_run_main(argc : LibC::Int, argv : LibC::Char**, user_main : (LibC::Int, LibC::Char** -> LibC::Int)) : LibC::Int
end

# Redefine main function
fun main(argc : Int32, argv : UInt8**) : Int32
  # Pass Crystal's main function as a callback
  LibAllegro.al_run_main(argc, argv, ->Crystal.main)
end

This is a breaking change because the macro redefine_main is removed.

One more thing: I expose main to Crystal as __crystal_c_main. This makes it possible to have a user-defined method named main, so kinda fixes what's described in #4761. Next, the compiler should disallow funs and methods with the same names, but I'll send that in a separate PR.

^ I decided it's better for now to expose it as main, because otherwise to redefine it one would need to use the same cryptic name. I'll later change the compiler to never expose fun main to Crystal code because it never needs to be invoked.

There's one TODO there that is fixed by the first commit in this PR. We can get rid of it after releasing the next version.

I also removed the single usage of redefine_main, which maybe was needed before, but removing it I got the SDL samples to work (they didn't work anymore).

This makes it possible to invoke `__crystal_main` from inside types and modules.
# - Invokes the given *block*
# - Handles unhandled exceptions
# - Invokes `at_exit` handlers
# - Flushes STDOUT and STDERR
Copy link
Contributor

Choose a reason for hiding this comment

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

Please, enclose STDOUT and STDERR in backticks `` to link 'em to docs.

end

# Executes the main user code. This normally is executed
# after initializing the GC and executing `at_exit` handlers.
Copy link
Contributor

Choose a reason for hiding this comment

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

[...] and before executing at_exit handlers.

?

# in Crystal (like `new` for classes) can be used.
def self.main(argc : Int32, argv : UInt8**)
main do
_crystal_main(argc, argv)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't be here main_user_code(argc, argv) instead?

This makes it simpler to redefine main with custom logic.
@ysbaddaden
Copy link
Contributor

Looks great!

One minor thing: sometimes we don't want a main, for example Android applications are shared objects, loaded from Java (JNI).

@asterite
Copy link
Member Author

@ysbaddaden Was that possible before this PR?

# Executes the main user code. This normally is executed
# after initializing the GC and before executing `at_exit` handlers.
#
# You should never invoke this method unless you need to
Copy link
Contributor

Choose a reason for hiding this comment

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

Would it be possible to raise early if this is executed twice? Seems like a bit of an edge case but might be worth protecting. This could be another PR though.

@asterite asterite merged commit c81b81d into crystal-lang:master Sep 19, 2017
#
# ```
# fun main(argc : Int32, argv : UInt8**) : Int32
# LibFoo.init_foo_and_invoke_main(argc, argv, ->Crystal.main)
Copy link
Contributor

Choose a reason for hiding this comment

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

Shouldn't ->Crystal.main be ->Crystal.main(Int32, UInt8**)?

Copy link
Member Author

Choose a reason for hiding this comment

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

If it's a lib call the compiler figures out the argument types.

Copy link
Contributor

Choose a reason for hiding this comment

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

Didn't know that, cushtie!

@ysbaddaden
Copy link
Contributor

@asterite no, it wasn't possible, but since it's touching main declarations, it could have been an opportunity to allow to skip generating a default main function. Anyway, no big deal.

@david50407
Copy link
Contributor

Can we also provide Crystal.main(argc : Int32, argv : UInt8**, envp : UInt8**) in this change?
envp is used in many C programs, maybe we can allow this argument and skip it first.

MSDN page for envp: https://msdn.microsoft.com/en-us/library/k104fy6h.aspx

@Sija
Copy link
Contributor

Sija commented Sep 19, 2017

@david50407 envp parameter is widely accepted, yet not standardised, see discussion on SO. btw, wouldn't it be redundant with access to ENV?

@mverzilli mverzilli added this to the Next milestone Sep 22, 2017
@Fryguy
Copy link
Contributor

Fryguy commented Sep 25, 2017

@asterite This is awesome, and is exactly what I was trying to accomplish myself, but couldn't figure out. This is really nice!

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

Successfully merging this pull request may close these issues.

Feature: Allow redefining main with a different name exposed in Crystal
8 participants