Any way to access global variable in Perl script from one module file?

Discussion in 'Perl Misc' started by Michael Yang, May 10, 2007.

  1. Michael Yang

    Michael Yang Guest

    I want to access one global variable saved in the main script from
    another one module. Here is what it looks like:

    A.pl: the main program, with one variable, e.g., $var, declared as
    global.
    #!/usr/bin/perl
    use strict;
    use warnings;
    use B;
    our $var = "hello";
    testB();

    B.pm: the module file, from which I want to access the $var variable
    in A.pl
    #!/usr/bin/perl
    package B;
    use strict;
    use warnings;
    require "A.pl"; ###########Actually I don't like this way, due
    to some problem
    sub testB{
    print "In B.pm, the variable is $var\n";
    ############Here I want the $var value in A.pl be accessible.
    }

    Is there a way doing this like in C language, we just need to declare
    it in B.pm, that the $var has been defined elsewhere, so it won't be
    checked during compile time but in runtime.

    The reason I don't want use 'require' statement, is the A.pl will be
    evaluated. But I only need it to check the declaration and assignment
    of the variable $var.

    Thanks all.
     
    Michael Yang, May 10, 2007
    #1
    1. Advertising

  2. Michael Yang <> wrote:
    > I want to access one global variable saved in the main script from
    > another one module. Here is what it looks like:


    > A.pl: the main program, with one variable, e.g., $var, declared as
    > global.
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > use B;
    > our $var = "hello";
    > testB();


    > B.pm: the module file, from which I want to access the $var variable
    > in A.pl
    > #!/usr/bin/perl
    > package B;
    > use strict;
    > use warnings;
    > require "A.pl"; ###########Actually I don't like this way, due
    > to some problem
    > sub testB{
    > print "In B.pm, the variable is $var\n";
    > ############Here I want the $var value in A.pl be accessible.
    > }


    > Is there a way doing this like in C language, we just need to declare
    > it in B.pm, that the $var has been defined elsewhere, so it won't be
    > checked during compile time but in runtime.


    If you have A.pl

    #!/usr/bin/perl
    use strict;
    use warnings;
    use Bxx;

    our $var = "hello";
    Bxx::testB();

    and Bxx.pm (I changed the name since there's already a packet called B)

    #!/usr/bin/perl
    package Bxx;
    use strict;
    use warnings;

    sub testB{
    print "In B.pm, the variable is $main::var\n";
    }

    1;

    it simply works;-) The 'main::' if front of the variable name
    tells that it's defined in the main package. If 'A' would be
    another package instead you would need 'use A;' at the start
    and would have to qualify '$var' with 'A::' in front of it,
    i.e. as '$A::var'.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, May 10, 2007
    #2
    1. Advertising

  3. Michael Yang

    Michael Yang Guest

    On May 10, 5:30 pm, (Jens Thoms Toerring) wrote:
    > Michael Yang <> wrote:
    > > I want to access one global variable saved in the main script from
    > > another one module. Here is what it looks like:
    > > A.pl: the main program, with one variable, e.g., $var, declared as
    > > global.
    > > #!/usr/bin/perl
    > > use strict;
    > > use warnings;
    > > use B;
    > > our $var = "hello";
    > > testB();
    > > B.pm: the module file, from which I want to access the $var variable
    > > in A.pl
    > > #!/usr/bin/perl
    > > package B;
    > > use strict;
    > > use warnings;
    > > require "A.pl"; ###########Actually I don't like this way, due
    > > to some problem
    > > sub testB{
    > > print "In B.pm, the variable is $var\n";
    > > ############Here I want the $var value in A.pl be accessible.
    > > }
    > > Is there a way doing this like in C language, we just need to declare
    > > it in B.pm, that the $var has been defined elsewhere, so it won't be
    > > checked during compile time but in runtime.

    >
    > If you have A.pl
    >
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > use Bxx;
    >
    > our $var = "hello";
    > Bxx::testB();
    >
    > and Bxx.pm (I changed the name since there's already a packet called B)
    >
    > #!/usr/bin/perl
    > package Bxx;
    > use strict;
    > use warnings;
    >
    > sub testB{
    > print "In B.pm, the variable is $main::var\n";
    >
    > }
    >
    > 1;
    >
    > it simply works;-) The 'main::' if front of the variable name
    > tells that it's defined in the main package. If 'A' would be
    > another package instead you would need 'use A;' at the start
    > and would have to qualify '$var' with 'A::' in front of it,
    > i.e. as '$A::var'.
    > Regards, Jens
    > --
    > \ Jens Thoms Toerring ___
    > \__________________________ http://toerring.de


    Thanks for your information.It really helps.
    But does it work with indirect invoking?
    For example:
    If I have one A.pl same as the one you gave, but in A.pl:
    I invoked another script "C.pl", in which the testB is called.
    A.pl:
    #!/usr/bin/perl
    use strict;
    use warnings;
    our $var = "hello";
    my @output = `perl C.pl`;

    C.pl:
    #!/usr/bin/perl
    use strict;
    use warnings;
    use Bxx;
    Bxx::testB();

    In this way, the $main:: refers to the script invoking the module's
    functions, that is C.pl here rather than A.pl.
    Is it due to the sub-process?

    Thanks.
     
    Michael Yang, May 10, 2007
    #3
  4. Michael Yang <> wrote:
    > But does it work with indirect invoking?
    > For example:
    > If I have one A.pl same as the one you gave, but in A.pl:
    > I invoked another script "C.pl", in which the testB is called.
    > A.pl:
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > our $var = "hello";
    > my @output = `perl C.pl`;


    > C.pl:
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > use Bxx;
    > Bxx::testB();


    > In this way, the $main:: refers to the script invoking the module's
    > functions, that is C.pl here rather than A.pl.
    > Is it due to the sub-process?


    This won't work because from A.pl you start a completely new
    child process that knows nothing about any variables set in
    the parent process that spawned it. In the example with the
    original A.pl and Bxx.pm you had a single process and the
    separation into A.pl and Bxx.pm is only something on source
    code level, when the script get started, everything gets put
    together. But if you start a program via backticks the ope-
    rating system creates a process with its own memory and that
    has no access to the memory of the parent process. Thus in
    this case you somehow have to pass the value of '$var' to
    the new process, the simplest method probably being via
    command line arguments.
    Regards, Jens
    --
    \ Jens Thoms Toerring ___
    \__________________________ http://toerring.de
     
    Jens Thoms Toerring, May 10, 2007
    #4
  5. On May 10, 11:29 am, Michael Yang <> wrote:
    > On May 10, 5:30 pm, (Jens Thoms Toerring) wrote:
    >
    >
    >
    > > Michael Yang <> wrote:
    > > > I want to access one global variable saved in the main script from
    > > > another one module.


    > > > Is there a way doing this like in C language, we just need to declare
    > > > it in B.pm, that the $var has been defined elsewhere, so it won't be
    > > > checked during compile time but in runtime.

    >
    > > it simply works;-) The 'main::' if front of the variable name
    > > tells that it's defined in the main package. If 'A' would be
    > > another package instead you would need 'use A;' at the start
    > > and would have to qualify '$var' with 'A::' in front of it,
    > > i.e. as '$A::var'.


    > Thanks for your information.It really helps.
    > But does it work with indirect invoking?
    > For example:
    > If I have one A.pl same as the one you gave, but in A.pl:
    > I invoked another script "C.pl", in which the testB is called.
    > A.pl:
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > our $var = "hello";
    > my @output = `perl C.pl`;
    >
    > C.pl:
    > #!/usr/bin/perl
    > use strict;
    > use warnings;
    > use Bxx;
    > Bxx::testB();
    >
    > In this way, the $main:: refers to the script invoking the module's
    > functions, that is C.pl here rather than A.pl.
    > Is it due to the sub-process?


    Yes, a separate process has a completely separate memory space. This
    is exactly the same as if one executable written in C called another -
    they wouldn't share variables either.

    There is a special variable %ENV that can carry information from
    parent to child but not the other way.

    I suspect you have an XY problem here. Can you explain what you are
    trying to achieve? There is probably no reason to create a new perl
    instance. Unless A.pl is a test harness for C.pl then C.pl should
    probably just be another module.
     
    Brian McCauley, May 10, 2007
    #5
  6. Michael Yang

    Michael Yang Guest

    On May 10, 7:59 pm, Brian McCauley <> wrote:
    > On May 10, 11:29 am, Michael Yang <> wrote:
    >
    >
    >
    >
    >
    > > On May 10, 5:30 pm, (Jens Thoms Toerring) wrote:

    >
    > > > Michael Yang <> wrote:
    > > > > I want to access one global variable saved in the main script from
    > > > > another one module.
    > > > > Is there a way doing this like in C language, we just need to declare
    > > > > it in B.pm, that the $var has been defined elsewhere, so it won't be
    > > > > checked during compile time but in runtime.

    >
    > > > it simply works;-) The 'main::' if front of the variable name
    > > > tells that it's defined in the main package. If 'A' would be
    > > > another package instead you would need 'use A;' at the start
    > > > and would have to qualify '$var' with 'A::' in front of it,
    > > > i.e. as '$A::var'.

    > > Thanks for your information.It really helps.
    > > But does it work with indirect invoking?
    > > For example:
    > > If I have one A.pl same as the one you gave, but in A.pl:
    > > I invoked another script "C.pl", in which the testB is called.
    > > A.pl:
    > > #!/usr/bin/perl
    > > use strict;
    > > use warnings;
    > > our $var = "hello";
    > > my @output = `perl C.pl`;

    >
    > > C.pl:
    > > #!/usr/bin/perl
    > > use strict;
    > > use warnings;
    > > use Bxx;
    > > Bxx::testB();

    >
    > > In this way, the $main:: refers to the script invoking the module's
    > > functions, that is C.pl here rather than A.pl.
    > > Is it due to the sub-process?

    >
    > Yes, a separate process has a completely separate memory space. This
    > is exactly the same as if one executable written in C called another -
    > they wouldn't share variables either.
    >
    > There is a special variable %ENV that can carry information from
    > parent to child but not the other way.
    >
    > I suspect you have an XY problem here. Can you explain what you are
    > trying to achieve? There is probably no reason to create a new perl
    > instance. Unless A.pl is a test harness for C.pl then C.pl should
    > probably just be another module.- Hide quoted text -
    >
    > - Show quoted text -


    Thank you all!
    I am designing a Test Harness for automation testing purpose.
    The A.pl I mentioned is the entrance script of the harness, I call it
    as main.pl here.
    In main.pl, I need to call the invocant that is processing the jobs of
    executing test cases, I call it Testrunner.pl here.
    So it should be like this:

    main.pl --------> Testrunner.pl ---------|---------------------
    >case1.pm

    ($handler)
    |---------------------->case2.pm

    |---------------------->case3.pm

    The $handler is a reference variable saved in the main.pl. I want it
    be accessible from each case module, case1.pm, case2.pm, without
    interference of Testrunner.pl. Because Testrunner.pl has been
    finalized as the agent of running test jobs. I have to keep it
    untouched.
    What I only could do now is to modify the main.pl and case module
    file. That's why I want to define the $handle as a global variable,
    and want it be accessed from the module file.
    How can I call Testrunner.pl from main.pl without spawning a separate
    child process? If it is a possibility, in this way, the solution Jens
    gave will work by $main::handler.

    Thanks
    Michael
     
    Michael Yang, May 10, 2007
    #6
  7. Michael Yang

    Michael Yang Guest

    >
    > main.pl --------> Testrunner.pl ---------|--------------------->case1.pm
    >
    > ($handler)
    > |---------------------->case2.pm
    >
    > |---------------------->case3.pm
    >


    sorry for the ambiguity of this graph.

    main.pl( $handler as its global variable) -------> Testrunner.pl -----
    > (case1.pm, case2.pm, case3.pm)


    Hope this would be clearer for understanding.
     
    Michael Yang, May 10, 2007
    #7
  8. On May 10, 1:38 pm, Michael Yang <> wrote:
    > On May 10, 7:59 pm, Brian McCauley <> wrote:


    > > I suspect you have an XY problem here. Can you explain what you are
    > > trying to achieve? There is probably no reason to create a new perl
    > > instance. Unless A.pl is a test harness for C.pl then C.pl should
    > > probably just be another module.
    > >

    > I am designing a Test Harness for automation testing purpose.
    > The A.pl I mentioned is the entrance script of the harness, I call it
    > as main.pl here.
    > In main.pl, I need to call the invocant that is processing the jobs of
    > executing test cases, I call it Testrunner.pl here.


    > The $handler is a reference variable saved in the main.pl. I want it
    > be accessible from each case module, case1.pm, case2.pm, without
    > interference of Testrunner.pl. Because Testrunner.pl has been
    > finalized as the agent of running test jobs. I have to keep it
    > untouched.
    > What I only could do now is to modify the main.pl and case module
    > file. That's why I want to define the $handle as a global variable,
    > and want it be accessed from the module file.


    The way you are using the term "global variable" is not the way it is
    usually used in most languages. (You haven't been using MUMPS have
    you?) Usually a global variable is only global within a given process.

    > How can I call Testrunner.pl from main.pl without spawning a separate
    > child process?


    You could do() it. However this would possibly give odd effects if you
    try to call Testrunner.pl more than once from main.pl. I say /
    possibly/ because if Testrunner.pl has written following best
    practices then it would probably run OK (and all you'd need to do is
    suppress the subroutine redefined warning).

    > If it is a possibility, in this way, the solution Jens
    > gave will work by $main::handler.


    Actually if Testrunner.pl already "thinks" that it "owns" main:: then
    you should use another namespace.
     
    Brian McCauley, May 10, 2007
    #8
  9. Michael Yang

    Michael Yang Guest

    On May 11, 1:07 am, Brian McCauley <> wrote:
    > On May 10, 1:38 pm, Michael Yang <> wrote:
    >
    >
    >
    > > On May 10, 7:59 pm, Brian McCauley <> wrote:
    > > > I suspect you have an XY problem here. Can you explain what you are
    > > > trying to achieve? There is probably no reason to create a new perl
    > > > instance. Unless A.pl is a test harness for C.pl then C.pl should
    > > > probably just be another module.

    >
    > > I am designing a Test Harness for automation testing purpose.
    > > The A.pl I mentioned is the entrance script of the harness, I call it
    > > as main.pl here.
    > > In main.pl, I need to call the invocant that is processing the jobs of
    > > executing test cases, I call it Testrunner.pl here.
    > > The $handler is a reference variable saved in the main.pl. I want it
    > > be accessible from each case module, case1.pm, case2.pm, without
    > > interference of Testrunner.pl. Because Testrunner.pl has been
    > > finalized as the agent of running test jobs. I have to keep it
    > > untouched.
    > > What I only could do now is to modify the main.pl and case module
    > > file. That's why I want to define the $handle as a global variable,
    > > and want it be accessed from the module file.

    >
    > The way you are using the term "global variable" is not the way it is
    > usually used in most languages. (You haven't been using MUMPS have
    > you?) Usually a global variable is only global within a given process.
    >
    > > How can I call Testrunner.pl from main.pl without spawning a separate
    > > child process?

    >
    > You could do() it. However this would possibly give odd effects if you
    > try to call Testrunner.pl more than once from main.pl. I say /
    > possibly/ because if Testrunner.pl has written following best
    > practices then it would probably run OK (and all you'd need to do is
    > suppress the subroutine redefined warning).
    >
    > > If it is a possibility, in this way, the solution Jens
    > > gave will work by $main::handler.

    >
    > Actually if Testrunner.pl already "thinks" that it "owns" main:: then
    > you should use another namespace.


    I am thinking about using 'require' to do this:
    @ARGV = ();
    require 'Testrunner.pl';

    In this way, the variable defined in the main script is in the same
    context as the Testrunner.pl, and could be accessed from the module
    file.
    But I found it slows the harness greatly, the performance is lowered.
    How to leaverage on this?
     
    Michael Yang, May 11, 2007
    #9
  10. On 11 May, 06:03, Michael Yang <> wrote:
    > On May 11, 1:07 am, Brian McCauley <> wrote:
    > > On May 10, 1:38 pm, Michael Yang <> wrote:


    > > > How can I call Testrunner.pl from main.pl without spawning a separate
    > > > child process?


    > > You could do() it. However this would possibly give odd effects if you
    > > try to call Testrunner.pl more than once from main.pl.


    > I am thinking about using 'require' to do this:
    > @ARGV = ();
    > require 'Testrunner.pl';
    >
    > In this way, the variable defined in the main script is in the same
    > context as the Testrunner.pl, and could be accessed from the module
    > file.


    Yes that's what I said. Well I said do() not require(). But the only
    difference in this conext is that main.pl _cannot_ run Testrunner.pl
    more than once.

    > But I found it slows the harness greatly, the performance is lowered.


    That seems highly counter-intuative. I would expect it to be a little
    faster as you are only loading perl once.

    How are you observing this? Is it possible that it's not the tests
    that are running slowly but rather something like an output buffering
    issue?

    > How to leaverage on this?


    Well the bunderbus thing would be to make a copy of the whole thing,
    main.pl, Testrunner.pl and at least one test case and check you still
    see the difference. Then cut bits out progressively checking at each
    stage that you still see the difference.

    Eventually you'll have a minimal but complete test case to illustrate
    the behaviour. If but this time you've not spotted what's happening
    then you should post the three files (which by now should be <20 lines
    each).
     
    Brian McCauley, May 11, 2007
    #10
  11. Michael Yang

    Michael Yang Guest

    On May 11, 2:43 pm, Brian McCauley <> wrote:
    > On 11 May, 06:03, Michael Yang <> wrote:
    >
    > > On May 11, 1:07 am, Brian McCauley <> wrote:
    > > > On May 10, 1:38 pm, Michael Yang <> wrote:
    > > > > How can I call Testrunner.pl from main.pl without spawning a separate
    > > > > child process?
    > > > You could do() it. However this would possibly give odd effects if you
    > > > try to call Testrunner.pl more than once from main.pl.

    > > I am thinking about using 'require' to do this:
    > > @ARGV = ();
    > > require 'Testrunner.pl';

    >
    > > In this way, the variable defined in the main script is in the same
    > > context as the Testrunner.pl, and could be accessed from the module
    > > file.

    >
    > Yes that's what I said. Well I said do() not require(). But the only
    > difference in this conext is that main.pl _cannot_ run Testrunner.pl
    > more than once.
    >
    > > But I found it slows the harness greatly, the performance is lowered.

    >
    > That seems highly counter-intuative. I would expect it to be a little
    > faster as you are only loading perl once.
    >
    > How are you observing this? Is it possible that it's not the tests
    > that are running slowly but rather something like an output buffering
    > issue?
    >
    > > How to leaverage on this?

    >
    > Well the bunderbus thing would be to make a copy of the whole thing,
    > main.pl, Testrunner.pl and at least one test case and check you still
    > see the difference. Then cut bits out progressively checking at each
    > stage that you still see the difference.
    >
    > Eventually you'll have a minimal but complete test case to illustrate
    > the behaviour. If but this time you've not spotted what's happening
    > then you should post the three files (which by now should be <20 lines
    > each).


    Thanks for your pointing it out, Brian.
    There is indeed the output buffering codes in the script, but I
    thought it works fine.
    Since it's a harness containing serveral large scripts, that I can't
    paste each piece of the codes, so I only put the key parts of the
    codes to simply illustrate what I am doing. Also the codes that might
    have relationship with output buffering.

    ### my main.pl script ####
    ### <codes omitted>####
    ## Start calling the Testrunner.pl ###
    @ARGV = ( "$testcase", ###The file with list of testcases in xml
    format
    "$paramFile", ###The file containing the
    configuration data
    "$logfile"); ###The file that log data is
    written to.

    do "$<path to runner>/Testrunner.pl";
    if ($@){
    #### codes to deal with errors ####
    }
    ###<codes omitted>####
    ### End of main.pl script ###

    #### Testrunner.pl script #######
    ### <codes to process parameters passed by main.pl> omitted###
    ### Set the autoflush to ON ####
    $| = 1;
    ### <codes to process list of testcases> omitted###
    ### Start to run the testcase subroutines in each module####
    foreach my $sr (@routines)
    {
    select STDOUT; #route print statements to STDOUT
    $logHandler->write($sr) # write the testcase info into logfile,
    defined in another module
    print "\n\t Executing => $sr";

    select $logFileHandle; # route print statements to the logfile,
    the one passed into by main.pl

    eval
    {
    no strict "refs";
    ($sr) -> ($params); #execution of the subroutines contained
    in each testcase module
    }
    }
    #### <codes dealing with the rest> omitted ####
    #### End of Testrunner.pl #####

    ### The module for one testcases, case1.pm#####
    package case1;
    #### <codes dealing with the member variables> omitted ####
    sub test1
    {
    ####<codes omitted> ####
    ###This will be directed to the logfile specified by the "select
    $logFileHandle" in Testrunner.pl#####
    print "Executing the test1...\n";
    $output = `...`; ## There is one child process spawned here, I
    saved the output into one variable.
    ### <rest of codes> omitted ####
    }
    ### <codes left> omitted ####
    1;
    #####End of case1.pm #######

    I just looked throught, and think these parts might have something
    with output buffering issue if there is any.
    These work fine and fast by invoking Testrunner.pl by spawning a child
    process, as discussed previously, except for the problem that the
    variable in main.pl can not be accessed from case1.pm.

    I am not sure which will affect and cause the buffering issues. If you
    have any simple example, could you show me one that might block the I/
    O that I could look into it?

    Thanks so much!
     
    Michael Yang, May 11, 2007
    #11
  12. [Micheal - please don't put all your comments at the end of the quoted
    material. I've tried to intersperse your responses in context. ]

    On May 11, 9:15 am, Michael Yang <> wrote:
    > On May 11, 2:43 pm, Brian McCauley <> wrote:
    > > On 11 May, 06:03, Michael Yang <> wrote:
    > > > On May 11, 1:07 am, Brian McCauley <> wrote:
    > > > > On May 10, 1:38 pm, Michael Yang <> wrote:


    > > > > > How can I call Testrunner.pl from main.pl without spawning a separate
    > > > > > child process?


    > > > > You could do() it. However this would possibly give odd effects if you
    > > > > try to call Testrunner.pl more than once from main.pl.


    > > > I am thinking about using 'require' to do this:


    > > Yes that's what I said. Well I said do() not require(). But the only
    > > difference in this conext is that main.pl _cannot_ run Testrunner.pl
    > > more than once.


    > Thanks for your pointing it out, Brian.


    Is a single run of main.pl do()ing Testrunner.pl more than once?

    As I mentioned before this could give odd effects. Since you are
    getting odd effects maybe this is the reason.

    > > > But I found it slows the harness greatly, the performance is lowered.

    >
    > > That seems highly counter-intuative. I would expect it to be a little
    > > faster as you are only loading perl once.

    >
    > > How are you observing this?


    This is the key question. You need to be sure if it's really running
    slowly.

    > > Is it possible that it's not the tests
    > > that are running slowly but rather something like an output buffering
    > > issue?


    > Since it's a harness containing serveral large scripts, that I can't
    > paste each piece of the codes, so I only put the key parts of the
    > codes to simply illustrate what I am doing. Also the codes that might
    > have relationship with output buffering.


    Output buffering issues are unlikely to be responsible for a real drop
    in performance so before you start looking for buffering issues you
    need to be sure the apparent loss of performance is illusory. If the
    loss of performance is real then you should look elsewhere for the
    cause.
     
    Brian McCauley, May 12, 2007
    #12
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. dpackwood
    Replies:
    3
    Views:
    1,839
  2. jubelbrus
    Replies:
    5
    Views:
    635
    JohnQ
    Jul 20, 2007
  3. Andrew Berg
    Replies:
    3
    Views:
    111
    Steven D'Aprano
    Oct 2, 2011
  4. Lim kiang Leng
    Replies:
    3
    Views:
    227
    Ben Morrow
    Jul 18, 2004
  5. Replies:
    3
    Views:
    204
    Josef Moellers
    Nov 1, 2007
Loading...

Share This Page